单词接龙
描述
单词接龙是一个与我们经常玩的成语接龙相类似的游戏,现在我们已知一组单词,且给定一个开头的字母,要求出以这个字母开头的最长的“龙”(每个单词都最多在“龙”中出现两次),在两个单词相连时,其重合部分合为一部分,例如beast和astonish,如果接成一条龙则变为beastonish,另外相邻的两部分不能存在包含关系,例如at和atide间不能相连。
输入
每个测试文件只包含一组测试数据,每组输入的第一行为一个单独的整数n(n<=20)表示单词数,以下n行每行有一个单词,输入的最后一行为一个单个字符,表示“龙”开头的字母。你可以假定以此字母开头的“龙”一定存在。
输出
对于每组输入数据,输出以此字母开头的最长的“龙”的长度。
下面的测试样例最后连成的“龙”为atoucheatactactouchoose。
输入样例 1
5
at
touch
cheat
choose
tact
a
输出样例 1
23
吐槽
这道题昨天写到了凌晨1点,哎,开始考虑要不要几点之后禁止写代码了,对睡眠伤害太大了,得不偿失啊。
坑点
- 注意,要求的是最长的龙的长度,所以重合部分尽量最小。
例子:bbaa 和 aacc 这两个单词的重合部分应该是a,而不是aa。 - 下面这句话我一直没看懂,一开始以为是两个单词不能呈现包含关系
但是结合上一点看,aa和aabc这两个单词是可以接龙的,重合部分为a。
所以这句话的意思应该是,重合部分不能覆盖前后某个单词。
相邻的两部分不能存在包含关系,例如at和atide间不能相连
- 一个单词可以出现两次,这就意味着如aba这样的单词可以自己接自己,重合部分为a。所以单词找接龙的时候没必要避开自己。
被上面这三点坑的死去活来。
解析
-
不过是一个深度优先搜索罢了,不断寻找子串,记录每个单词的使用次数,注意状态的恢复。
-
关键部分是寻找子串,注意上面三个坑点。
-
一开始还打算把每个单词能接龙的单词都找出来,后来看看网上的代码,发现没这个必要。但还是把自己的代码摆出来吧。我的代码复杂了,关键还是看看我的代码上面的思想吧。
寻找重合部分的办法
-
我的方法:
单词a,b,从a的尾部(保证重合部分最短)开始不断寻找和b的首字母相同的位置,然后看从这个位置到结尾和b是否相同。注意重合部分不要覆盖单词。 -
网上看到的更好的办法:
strlen从1到min(len(a),len(b))-1遍历,看两个单词strlen长度的部分是否重合。
代码
int len;
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
int ans;
char* tmp;
struct Word{
char s[1000];
int childnum;
struct Word* n[22];
int childlen[22];
int AccurNum;
}word[22];
int Strstr(char* a,char b,int t){
for(int i = t ;i > 0;i--)
if(a[i] == b )
return i;
return -1;
}
void dfs(struct Word* w,int len){
for(int i = 0;i < w->childnum;i++){
if(w->n[i]->AccurNum >= 2)continue;
w->n[i]->AccurNum++;
len += w->childlen[i];
if(len > ans){
ans = len;
}
dfs(w->n[i],len);
w->n[i]->AccurNum--;
len -= w->childlen[i];
}
if(len > ans)ans = len;
}
void judge(struct Word* a,struct Word* b){//判断b后面是否能接a
int s;
s = Strstr( b->s,(a->s)[0],(int)strlen(b->s)-1);//a的首字母在b中的位置
while( s > 0 ){
int flag = 1;
int j = 0;
int i;
for( i = s ; i < strlen(b->s) && j < strlen(a->s) ;i++){
if(b->s[i] != a->s[j++]){
flag = 0;
break;
}
}
if(flag && j != strlen(a->s)){
b->childlen[b->childnum] = (int)strlen(a->s)-j;
b->n[b->childnum++] = a;
return;
}
s = Strstr(b->s, (a->s)[0],s-1);
}
}
int main(){
int n;char l;
scanf("%d",&n);
for(int i = 0;i < n;i++){
scanf("%s",word[i].s);
word[i].AccurNum = word[i].childnum = 0;
}
scanf("%c",&l);
scanf("%c",&l);
for(int i = 0;i < n;i++){
judge(&word[i], &word[i]);
for(int j = i+1;j < n;j++){
judge(&word[i], &word[j]);
judge(&word[j], &word[i]);
}
}
ans = 0;
for(int i = 0;i < n;i++){
if(word[i].s[0] == l){
word[i].AccurNum++;
dfs(&word[i],(int)strlen(word[i].s));
word[i].AccurNum--;
}
}
printf("%d\n",ans);
}