照例先上题目链接:https://www.luogu.org/problemnew/show/P1019
一拿到题是懵的,读了好几遍题目才确定题意,想了半天都在想怎么样才能模拟把字符串输出出来。果然对于这种含有模拟的题目我还是很不拿手。
由于对这个题目毫无思路,在队友@TDD的启(讲)发(解)下,我才勉强对这个题目有了新的认识。
这题根本就不需要把字符输出出来啊!
下面是思路:
首先题目要求,求出最长的字符串,那么我们就需要找到每两个单词之间最短的重合长度(最小重叠部分),
举个例子,abcd和dddddd,他们合并之后是abcddddddd,他们的最小重叠长度是1(我也不知道对不对,如果不对的话请给我留言,谢谢大家啦)
题目还给出了一个首字符,那么我们就直接根据首字符进行暴力DFS,如果可以接龙,那么就直接把合并上的长度加上去,直到所有的字符都不能合并为止。每一次DFS都要对于长度求一个max。
这就是大体思路,但是我们注意到,DFS里面需要找很多次单词的接龙单词,这咋找啊!我哪知道这个单词后面能接哪一个单词啊!所以我们就需要对所有的字符串进行【预处理】,func(i,j)表示第i个字符串后面接第j个字符串的最小重叠长度。这样预处理完了之后,就可以愉快的DFS辽。
下面上代码:
#include <bits/stdc++.h>
using namespace std;
const int maxn = 30;
int num[maxn][maxn];
int used[maxn];
int ans = 0;
int tmp = 0;
int n;
void init()
{
memset(num,0,sizeof(num));
memset(used,0,sizeof(used));
}
string str[maxn];
int func(int a,int b)
{
for(int i=str[a].size()-1;i>=0;i--)
{
int pb = 0;
int j;
for(j=i;j<str[a].size();j++)
{
if(str[a][j]==str[b][pb] && pb<str[b].size())
{
pb++;
}
else
{
break;
}
}
if(j>=str[a].size())
{
return str[a].size()-i;
}
}
return -1;
}
void dfs(int s)
{
bool found = false;
for(int i=0;i<n;i++)
{
if(used[i]<2 && num[s][i]!=-1 && num[s][i]!=str[i].size() && num[s][i]!=str[s].size())
{
found = true;
tmp += str[i].size()-num[s][i];
used[i]++;
dfs(i);
tmp -= str[i].size()-num[s][i];
used[i]--;
}
}
if(!found)
{
ans = max(ans,tmp);
}
}
int main()
{
while(cin>>n)
{
for(int i=0;i<n;i++)
{
cin>>str[i];
}
cin>>str[n];
for(int i=0;i<n;i++)
{
for(int j=0;j<n;j++)
{
num[i][j] = func(i,j);
}
}
for(int i=0;i<n;i++)
{
if(str[i][0]==str[n][0])
{
used[i]++;
tmp = str[i].size();
dfs(i);
used[i]--;
}
}
cout<<ans<<endl;
}
return 0;
}
总结:感觉这个题目不仅思路很混乱,而且代码实现也比较复杂。果然还是自己太蒻了!