您的位置:首页 > 其它

单词接龙(DFS)

2017-09-09 11:53 393 查看
题目描述 Description

单词接龙是一个与我们经常玩的成语接龙相类似的游戏,现在我们已知一组单词,且给定一个开头的字母,要求出以这个字母开头的最长的“龙”(每个单词都最多在“龙”中出现两次),在两个单词相连时,其重合部分合为一部分,例如beast和astonish,如果接成一条龙则变为beastonish,另外相邻的两部分不能存在包含关系,例如at和atide间不能相连。

输入描述 Input Description

输入的第一行为一个单独的整数n(n<=20)表示单词数,以下n行每行有一个单词,输入的最后一行为一个单个字符,表示“龙”开头的字母。你可以假定以此字母开头的“龙”一定存在。

输出描述 Output Description

只需输出以此字母开头的最长的“龙”的长度

样例输入 Sample Input

5

at

touch

cheat

choose

tact

a


样例输出 Sample Output

23


数据范围及提示 Data Size & Hint

(连成的“龙”为atoucheatactactouchoose)


限制

时间限制: 1 s

空间限制: 128000 KB

个人思路

1、有两种情况,龙头和非龙头,龙头情况最为简单,判断第一个字符是否相同即可。

2、非龙头的情况,先判断使用次数是否达到2次了,如果不是,则比较当前选中的字符串和龙字符串,找到最长的相同部分拼接即可,当然还要满足非包含关系。

3、遍历完所有情况就能找到最长的那条龙。

#include<cstdio>
#include<cstring>
#include<iostream>
using namespace std;
short n;
int Maxstr=0;
char a[21][30];//储存输入
int book[30];//标记,记录使用次数
void DFS(char str[])//str[]为当前的龙
{
char str2[500];
if(strlen(str)>Maxstr)
{
Maxstr=strlen(str);
}
for(int i=1;i<=n;i++)
{
if(strlen(str)==1&&a[i][0]==str[0])//接入龙头
{
strcpy(str2,str);
int k=1;
int j=1;
while(j<strlen(a[i]))
str[k++]=a[i][j++];
str[k]='\0';
book[i]++;
DFS(str);
//回退!!
strcpy(str,str2);
book[i]--;
}
else if(book[i]<2)
{
bool flag=false;
bool now,pre=false;
int k;
int temp=min(strlen(str),strlen(a[i]));
for(k=1;k<=temp;k++)//比较所有情况,一个字母相同,两个字母相同……
{
now=true;
int k1=0;
int k2=strlen(str)-k;
for(int j=0;j<k;j++)
{
if(str[k2++]!=a[i][k1++])
{
now=false;
break;
}
}
if(!now&&pre)//之前情况满足,现在不满足了,说明现在是字母最多的情况了,并且关系为不包括
{
flag=true;
break;
}
pre=now;
}
if(flag)
{
strcpy(str2,str);
int m=strlen(str);
--k;//下标是从0开始的
while(k<strlen(a[i]))
str[m++]=a[i][k++];
str[m]='\0';
book[i]++;
DFS(str);
//回退!!
strcpy(str,str2);
book[i]--;
}
}
}
}
int main()
{
char c;
char str[1000];
scanf("%d",&n);
for(int i=1;i<=n;i++)
scanf("%s",&a[i]);
//此处使用scanf("%c",&c)的话,会出错,printf("c:%d",c);得到的10,'\n'的ASCII码,是获取之前的一个回车符,故使用cin>>c;
cin>>c;
for(int i=0;i<30;i++)
book[i]=0;
str[0]=c;
str[1]='\0';
DFS(str);
printf("%d\n",Maxstr);
return 0;
}


个人总结

这是2000年NOIP全国联赛普及组NOIP全国联赛提高组的一道题,确实有点麻烦。

说一下处理过程中的一些问题吧。

问题一: 传参

龙传递的过程中是不断在改变的,所以必须保留之前的龙,等下一层调用完成时,回退龙, 并且回退使用次数。这个问题是后来测试错误才发现的。

问题二:如何找到当前选中的字符串与龙头最大重叠部分,并且保证不是包含关系。

我是这样处理的,为了描述简单,设当前选中的字符串为s1,龙字符串为s2。

尝试一个字母相同、两个字母相同、三个字母相同……,直到min(strlen(s1),strlen(s2))相同为止。

pre记录前一种情况是否相同,now记录当前情况是否相同。当pre=true,now=false,则说明pre那种情况是s1和s2最长重叠部分,此时也保证了两者之间不是包含关系。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  dfs