洛谷 p1019 单词接龙
题目描述
单词接龙是一个与我们经常玩的成语接龙相类似的游戏,现在我们已知一组单词,且给定一个开头的字母,要求出以这个字母开头的最长的“龙”(每个单词都最多在“龙”中出现两次),在两个单词相连时,其重合部分合为一部分,例如 beast和astonish,如果接成一条龙则变为beastonish,另外相邻的两部分不能存在包含关系,例如at和 atide 间不能相连。
输入输出格式
输入格式:
输入的第一行为一个单独的整数n(n≤20)表示单词数,以下n 行每行有一个单词,输入的最后一行为一个单个字符,表示“龙”开头的字母。你可以假定以此字母开头的“龙”一定存在.
输出格式:
只需输出以此字母开头的最长的“龙”的长度
分析
本题还是一道dfs问题 重要的是如何处理给出的单词 以及如何构建一个dfs
首先我们注意到,想要找到最长的“龙”,根据贪心的原则,重合部分要取最小 比如 asdd 和ddas 这两个“单词”,合起来就是adddas 也就是只重合一个字母 而不是asddas 这一点是需要注意的
首先为了dfs的方便 我们可以构造一个数组 p[i][j] 代表 i 单词在前 j 单词在后的时候会重合多少字母 还是asdd和ddas的例子 如果i 单词是asdd,j 单词是ddas 那么p[i][j]=1,p[j][i]=2
至于构造的方式 看下面的代码就好了 注意一定是最小的重合部分。
代码:
#include<bits/stdc++.h> using namespace std; string s[30]; char d; int n,vis[21],p[30][30],ans=-1,an=0; void ff(int x,int y) { int k,kx; int ky=0; int flag=1; for(k=s[x].size()-1;k>=0;k--) { for(kx=k;kx<=s[x].size()-1;kx++) { if(s[x][kx]!=s[y][ky++]) { flag=0; break; } } if(flag) //只要有重合部分就跳出,这样保证了重合的是最小的 { p[x][y]=s[x].size()-k; return; } ky=0; flag=1; } return ; } void dfs(int x) { int i,flag=0; for(i=0;i<n;i++) if(vis[i]<2&&p[x][i]!=0&&s[x].size()!=p[x][i]&&s[i].size()!=p[x][i]) { flag=1; an+=s[i].size()-p[x][i]; vis[i]++; dfs(i); vis[i]--; an-=s[i].size()-p[x][i]; } if(!flag) //如果没有新的单词可以“接龙”,判断是否是更长的“龙”并返回 ans=max(ans,an); return; } int main() { int i,j; cin>>n; for(i=0;i<n;i++) { cin>>s[i]; } for(i=0;i<n;i++) for(j=0;j<n;j++) { ff(i,j); } cin>>d; for(i=0;i<n;i++) { if(s[i][0]==d) { vis[i]++; an=s[i].size(); //不要忘了这一句 而且是 = 不是+=!! dfs(i); vis[i]=0; } } cout<<ans; }