单词接龙(DFS)

来源:互联网 发布:国际数据流量怎么开通 编辑:程序博客网 时间:2024/05/18 18:47

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

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

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

样例输入 Sample Input

5attouchcheatchoosetacta

样例输出 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最长重叠部分,此时也保证了两者之间不是包含关系。
原创粉丝点击