DFS 深搜。
加入第一个单词时,我们判断它能不能是第一个单词,这只需要比较这个单词的第一个字符,与数据给定的字符是否一样就行了。
加入后面的字符时,我们需要检查这个单词是否可以 与前面的单词对接起来, 这个检查由check 函数实现。
check函数:枚举 k 从 1 到 min(2个单词的长度), 作为暴力枚举2个单词有 k 个重叠字符。 所以说, 当枚举到 有 k 个重叠字符时,我们枚举 要拼接的2个单词中的前面的单词 的后 k 位 和 后面的单词 的前 k 位,一旦有 k 可以 使 这 2 个单词的 k 位的每一位都相等, 我们就返回 k, 因为显然重叠的越少, 最后达到的长度越长。
至于 枚举 k 到min (2个单词的长度),是因为 重叠部分的长度肯定不能 >= 其中任意一个单词的长度, 否则就是包含或者相等了。
代码:
#include <iostream>
#include <cstdio>
#include <cstring>
#include <queue>
using namespace std;
const int MAXN = 100 + 10;
int n, ans = 0;
int use[MAXN];
struct WORD{
char a[MAXN];
}s[MAXN];
int check(int l, int n)
{
int l_l = strlen(s[l].a), l_n = strlen(s[n].a);
for(int k = 1; k < min(l_n, l_n); k ++)
{
bool h = 1;
for(int i = l_l-k, j = 0; i < l_l, j < k; i ++, j ++)
{
if(s[l].a[i] != s[n].a[j])
{
h = 0;
break;
}
}
if(h)
return k;
}
return 0;
}
void dfs(int last, int len)
{
if(!last)
{
for(int i = 1; i <= n; i ++)
{
if(s[i].a[0] == s[0].a[0])
{
if(use[i] < 2)
{
use[i] ++;
dfs(i, strlen(s[i].a));
use[i] --;
}
}
}
}
else{
ans = max(ans, len);
for(int i = 1; i <= n; i ++)
{
int x = check(last, i);
if(x && use[i] < 2)
{
use[i] ++;
dfs(i, len+strlen(s[i].a)-x);
use[i] --;
}
}
}
}
int main()
{
scanf("%d", &n);
for(int i = 1; i <= n; i ++)
scanf("%s", s[i].a);
scanf("%s", s[0].a);
dfs(0,1);
cout << ans << endl;
return 0;
}