https://www.luogu.org/problemnew/show/P1019 落骨
分3个板块 :
1. 求出两个字符串最小的重复长度
由题目要求 ,在比较的过程中,一个串不能是另一个串的子串,所以 i != len。 for里面的写法很精妙。。如果找到最小的重复长度,就马上return,输出 ;如果找不到,return 0代表最小重复长度是0;
2. dfs遍历
如果找到一个s[i] ,不需要和 ans 拼接,只需要把s[i] 接着dfs,找到下一个串就行了。 l 用来记录每次加上s[i] 之后的长度,并且不断更新sum。如果一个串被用了达到2次,就不能用。
3. 输入输出
这部分重要的是 dfs( ' '+ans , 1 ),感觉无论是' '+ans,还是‘1’都很有意义。。
' '+ans是因为在第一次对ans和别的串进行找 最小的重复长度时,如果不加' ',则 minlen中 x.length() =1,在for中无法运行,最终只能return 0,这个和实际情况肯定是不符的; 加上 ' '之后可以避免这个情况。
( 如果在s[i]中有单个字母的情况,例如 'a',和"ab"在 minlen 中比较时, ' ' 不加无影响。因为如果这两者有最小重复长度,也是不行的,因为a是 ab的子串,return 0; 如果无最小长度,就return 0;所以无论怎么样都是 return 0的。 这段自动忽略)
初始 dfs( ' '+ans , 1 )的 ‘1’我还是有点不十分理解。大概是因为 题目要求 一定是存在以 龙头字母为开始的s[i],所以最小长度必须为 1吧 。
#include<iostream> #include<cstdio> #include <cctype> #include<algorithm> #include<cstring> #include<cmath> #include<string> #include<cmath> #include<set> #include<vector> #include<stack> #include<queue> #include<map> using namespace std; #define ll long long #define mem(a,x) memset(a,x,sizeof(a)) #define se second #define fi first const int INF= 0x3f3f3f3f; const int N=1e5+5; int n,sum,vis[30]={0}; string ans, s[25]; int minlen(string x,string y) //最小重合长度 { int len=min( x.length(), y.length()); for(int i=1;i<len;i++) //i!=len 防止是字串 { int flag=0; for(int j=0;j<i;j++) if( x[ x.length()-i+j] != y[j]) flag=1; if(!flag) return i; } return 0; } void dfs(string x, int l) //拼接 { sum= max( sum, l); for(int i=1;i<=n;i++) { if( vis[i]>=2 ) continue; int mlen = minlen( x, s[i]); if( mlen==0) continue; vis[i]++; dfs(s[i], l+ s[i].length() -mlen); vis[i]--; } return; } int main() { cin>>n; for(int i=1;i<=n;i++) cin>>s[i]; cin>>ans; sum=0;//答案 dfs(' '+ans, 1); cout<<sum<<endl; }