单词接龙
问题描述:单词接龙是一个与我们经常玩的成语接龙相类似的游戏,现在我们己知一组单词,且给定一个开头的字母,要求出以这个字母开头的最长的“龙”(每个单词都最多在“龙" 中出现两次),在两个单词相连时,其重合部分合为一部分,例如beast和astonish,如果接成一条龙则变为beastonish,另外相邻的两部分不能存在包含关系,例如at和atide间不能相连。
输入:输入的第一行为一个单独的整数n(n<=20)表示单词数,以下n行每行有一个单词,输入的最后一行为一个单个字符,表来“龙”开头的字母。你可以假定以此字母开头的“龙"一定存在。
输出:只需输出以此字母开头的最长的“龙”的长度
样例:
输入
5
at
touch
cheat
choose
tact
a
输出
23 (连成的“龙”为atoucheatactactouchoose)
#include
#include
#include
using namespace std;
int n,ans=0,b[50],maxn;
char a[50][100],s,f[50][100];
int js(char a[],char b[])
{
int la=strlen(a);
int lb=strlen(b);
char x=b[0];
int j,l;
bool p;
p=false;
for (j=la-1;j>=0;--j)//从当前接龙的最后一个单词的最后一位向前搜索
if (a[j]==x)//找寻当前接龙的最后一个单词中与要加入接龙单词的首字母相同的位置
{
p=true;
for (l=j+1;l
if (a[l]!=b[l-j])
{
p=false;
break;
}
if (p) break;//重叠的位数最少,加入的位数就越多哦,所以从后往前找能保证找到最少重叠位数不再寻找,直接退出寻找过程
}
if (p) return lb-la+j;
else return 0; //加入位数为0,有两种可能,一种是无法连接,一种是完全包含
}
void search(int num)
{
int l,j,y,i;
bool pd;
pd=false;//如果已经没用单词可以相连,则得到了一个答案
for (l=1;l<=n;l++)
if (b[l]<2)//由题目的每个单词最多可用两次,若还没用到两次,可继续使用
{
y=js(f[num-1],a[l]);//计算将该单词加入接龙,接龙可以增加的位数
if (y!=0)//如果可增加的位数为0,即该单词无法与接龙相连
{
pd=true;
b[l]++;
strcpy(f[num],a[l]);
ans+=y;
search(num+1);
b[l]--;
ans-=y;
}
}
if (pd==false)//更新最大值
if (ans>maxn)
maxn=ans;
return;
}
int main()
{
int i;
scanf("%d\n",&n);
for (i=1;i<=n;i++)
{
cin>>a[i];
b[i]=0;
}
cin>>s;
for (i=1;i<=n;i++)//寻找接龙的开头单词
if (a[i][0]==s)
{
memset(b,0,sizeof(0));
b[i]++;
strcpy(f[1],a[i]);
ans+=strlen(a[i]);//将第一个单词的长度直接加入答案
search(2);//搜索接龙的第二个单词
ans=0;
b[i]--;//回溯
}
cout<<maxn<<endl;
return 0;
}
这道题着实费了老大的劲,一下午加一晚上的大好时光都耗上了,不停地调试寻找问题所在,最后选择重新编,现在看到的是重新编的程序,至于那个依然有两组没过的旧版就先放过吧,我也想放过我自己TAT,不过长时间的调试也不是一无是处,让我更了解搜索回溯的过程,如果大家想了解回溯,不妨多调试一下。