题目链接:https://www.luogu.org/problemnew/show/P1019
这题就是搜索dfs遍历所有连接情况,找最大的。
难点在于:重合部分的处理,怎样获取这个重合长度。
另外,容易理解错的2点
1.一个字符开头,必定是包含的,所以要在主函数中for一个一个找哪个单词包含了它,字符不能放在搜索函数中(搜索函数考虑的就是不包含的情况!),不然没有答案。
2.关于重叠部分选取:
不是所有重合的都重合起来;
而是选最小的重合部分,单词接龙嘛,只要有一个字符尾首重合(即相同)就符合接龙的游戏规则,而且要求最长龙,必须选最小重合部分,这就是本题贪心规则。贪心没什么难的,就是容易理解错。
如:beaaa,aaas,重合长度为1不是3;baskask,askasklp重合长度为3不是6!
1 #include <iostream> 2 #include <string> 3 #include <algorithm> 4 #include <cstdio> 5 #include <cstring> 6 using namespace std; 7 typedef long long ll; 8 typedef unsigned long long ull; 9 const int maxn=1e3+5; 10 const int inf=1e9; 11 string s[maxn],be; 12 int vis[maxn];//标记数组 13 int n,ans; 14 15 int jud(string s1,string s2)//求最小重合长度函数,例子bask,asklp跟一遍就明白 16 { 17 int len1=s1.length(),len2=s2.length(); 18 int f=0; 19 for (int i=1;i<min(len1,len2);i++)//注意:小于最短的本身减1!这就把包含情况去掉了!例如ask,askl就是0,非常巧妙! 20 { 21 f=0; 22 for(int j=0;j<i;j++) 23 { 24 if(s1[len1-i+j]!=s2[j]) { f=1; break; } 25 } 26 27 if(!f) return i;//都没有变化,符合要求了返回最小重合 28 } 29 30 return 0; 31 } 32 33 34 void so(string nowstr,int nowlen) 35 { 36 ans=max(ans,nowlen);//更新答案最长长度 37 38 for(int i=1;i<=n;i++) 39 { 40 if(vis[i]>=2) continue; 41 int c=jud(nowstr,s[i]);//获取重合部分长度(因该是最小重合长度就行(因为有一个字符重合就能连接上!),多了不管) 42 43 if(c>0) //有重叠部分就开始(包含部分已在jud函数中考虑到删去) 44 { 45 vis[i]++; 46 so(s[i],nowlen+s[i].length()-c); 47 vis[i]--; 48 } 49 } 50 } 51 52 int main() 53 { 54 ios::sync_with_stdio(false); cin.tie(0); 55 56 cin>>n; 57 for(int i=1;i<=n;i++) cin>>s[i]; 58 cin>>be; 59 60 for(int i=1;i<=n;i++)//第一个字符必包含,所以放在搜索函数外面 61 { 62 string st=""; 63 st+=s[i][0];//因为字符s[i][0]不能直接和字符串be直接比较所以转换一下 64 if(st==be) 65 { 66 vis[i]++; 67 so(s[i],s[i].length()); 68 vis[i]--; 69 } 70 } 71 72 cout<<ans<<endl; 73 74 return 0; 75 }
完。