单词接龙C语言解决

单词接龙

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

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

输出
对于每组输入数据,输出以此字母开头的最长的“龙”的长度。
下面的测试样例最后连成的“龙”为atoucheatactactouchoose。

输入样例 1
5
at
touch
cheat
choose
tact
a

输出样例 1
23

吐槽

这道题昨天写到了凌晨1点,哎,开始考虑要不要几点之后禁止写代码了,对睡眠伤害太大了,得不偿失啊。

坑点

  1. 注意,要求的是最长的龙的长度,所以重合部分尽量最小
    例子:bbaa 和 aacc 这两个单词的重合部分应该是a,而不是aa。
  2. 下面这句话我一直没看懂,一开始以为是两个单词不能呈现包含关系
    但是结合上一点看,aa和aabc这两个单词是可以接龙的,重合部分为a。
    所以这句话的意思应该是,重合部分不能覆盖前后某个单词

相邻的两部分不能存在包含关系,例如at和atide间不能相连

  1. 一个单词可以出现两次,这就意味着如aba这样的单词可以自己接自己,重合部分为a。所以单词找接龙的时候没必要避开自己

被上面这三点坑的死去活来。

解析

  1. 不过是一个深度优先搜索罢了,不断寻找子串,记录每个单词的使用次数,注意状态的恢复。

  2. 关键部分是寻找子串,注意上面三个坑点。

  3. 一开始还打算把每个单词能接龙的单词都找出来,后来看看网上的代码,发现没这个必要。但还是把自己的代码摆出来吧。我的代码复杂了,关键还是看看我的代码上面的思想吧。

寻找重合部分的办法

  • 我的方法:
    单词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);
    
    
}

猜你喜欢

转载自blog.csdn.net/qq_39500214/article/details/89407318
今日推荐