NOI:8783 单词接龙

题目链接


8783:单词接龙


总时间限制: 
1000ms 
内存限制: 
65536kB
描述

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

输入
输入的第一行为一个单独的整数n(n<=20)表示单词数,以下n行每行有一个单词(只含有大写或小写字母,长度不超过20),输入的最后一行为一个单个字符,表示“龙”开头的字母。你可以假定以此字母开头的“龙”一定存在。
输出
只需输出以此字母开头的最长的“龙”的长度。
样例输入
5
at
touch
cheat
choose
tact
a
样例输出
23
提示
连成的“龙”为atoucheatactactouchoose
来源
NOIP2000复赛 普及组 第四题

#------------------------------------------------------------------------------#

此题乍一看,似乎并不是很难,但需要处理以下一些情况:
1.单词不能包含
2.每个单词可以用2次
3.重合部分长度需减去
4.重合长度是不确定的。

现在谈谈大体思路:

首先此题一定用深搜。

其次存单词时,从f[1]开始存,而最后一个表示开头的字母存f[0]。
why?我们接龙时就直接从f[0]开始便不需要处理开头的单词。

接下来处理问题:
1.关于包含,只需查到长度len-1即可,如果还不符合便不符合。
2.我们可以定义一个v数组,判断单词使用次数,在使用前判断if(v[i]<2)每使用一次变v[i]++,注意递归完后v[i]--

然后先看4.在判断单词是否可以连接时,我们从i=0,循环到i=n,即所有单词查完,如果单词可用便接着循环,查待连接单词,如果某一位与可连接单词相同,便再循环,定义一个临时变量t,从后一位开始,查,如果不同,直接t=0,break,出循环后if(t)便代表可连接,开始递归下一个,别忘了v[i]++。(此部分便是核心算法)

关于3.在判断可连接时,总长度L便加上两个单词长度,然后前面的最后盘点是否完全符合的循环计数变量定义在外面,L直接减去它便是接龙长度了。

不知道是否听懂……
直接上代码:

[cpp]  view plain  copy
  1. #include<cstdio>  
  2. #include<cstring>  
  3. struct le//定义结构体可以更方便  
  4. {  
  5.     char s[22];//单词  
  6.     int len;//单词长度  
  7.     int v;//单词访问次数  
  8. }c[22];//单词数量不超过20个,所以c[22]即可  
  9. int n;  
  10. int maxn;  
  11. void jl(int x,int len)//两个参数分别代表待连接单词的结构体下标和长度  
  12. {  
  13.     for(int i=1;i<=n;i++)  
  14.         if(c[i].v<2)//判断访问次数  
  15.             for(int j=0;j<c[x].len;j++)//查待连接单词的每一个字母  
  16.                 if(c[x].s[j]==c[i].s[0])  
  17.                 {  
  18.                     int k=1;//将循环变量定义在外面,方便以后相减  
  19.                     int t=1;//临时变量(其实bool就行)  
  20.                     for(int l=j+1;l<c[x].len&&k<c[i].len;k++,l++)//l表示待连接单词下标,k是可连接单词下标,所以在循环条件中需满足它们小于(因为不能包含,所以不能等于)单词长度  
  21.                         if(c[x].s[l]!=c[i].s[k])  
  22.                         {  
  23.                             t=0;  
  24.                             break;  
  25.                         }  
  26.                     if(t)  
  27.                     {  
  28.                         c[i].v++;  
  29.                         jl(i,len+c[i].len-k);//更新长度和下标后递归  
  30.                         c[i].v--;//完成后一定记得--  
  31.                     }  
  32.                 }  
  33.     if(len>maxn)  
  34.         maxn=len;//不解释  
  35. }  
  36. int main()  
  37. {  
  38.     scanf("%d",&n);  
  39.     for(int i=1;i<=n;i++)  
  40.     {  
  41.         scanf("%s",c[i].s);  
  42.         c[i].len=strlen(c[i].s);  
  43.     }  
  44.     scanf("%s",c[0].s);  
  45.     c[0].len=strlen(c[0].s);//直接将开头字母存在0号结构体  
  46.     jl(0,c[0].len);//开头字母当第一个单词处理  
  47.     printf("%d",maxn);  
  48. }  

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值