竞赛题目讲解-【NOIP2000复赛 普及组】单词接龙
2017-07-12 17:19
344 查看
8783:单词接龙
Description单词接龙是一个与我们经常玩的成语接龙相类似的游戏,现在我们已知一组单词,且给定一个开头的字母,要求出以这个字母开头的最长的“龙”(每个单词都最多在“龙”中出现两次),在两个单词相连时,其重合部分合为一部分,例如beast和astonish,如果接成一条龙则变为beastonish,另外相邻的两部分不能存在包含关系,例如at和atide间不能相连。
Input
输入的第一行为一个单独的整数n(n<=20)表示单词数,以下n行每行有一个单词(只含有大写或小写字母,长度不超过20),输入的最后一行为一个单个字符,表示“龙”开头的字母。你可以假定以此字母开头的“龙”一定存在。
Output
只需输出以此字母开头的最长的“龙”的长度。
Sample Input
5 at touch cheat choose tact a
Sample Output
23
Hint
连成的“龙”为atoucheatactactouchoose
题目讲解
这道题直接看十分复杂,“接龙”时的规则特别多,我们可以放在后面一个个来处理。
首先是变量的选择。它的输入是字符串,那么我们就有2种选择:字符串string或char数组,两种方法都可以解出题目。但是,作者在这里推荐使用string,这是C++的一个新特性,因此关于它的函数也特别多,便于解题。虽说string的操作特别慢(这也是一些题不能用string的原因),但这道题的操作量并不是特别大,还不至于超时。
我们先读入n个单词(string用cin读入),然后读入开头字母。这里有一个误区——我们往往会默认为这道题的开头字母只会指向一个单词,但是出现相同字母开头的单词几率特别大,我们必须找到所有可以从它开始的单词。
顺着题意,我们需要进行接龙。既然这是一道搜索题,我们就可以选择深度优先搜索和广度优先搜索。这里由于作者用的是string,就不得不用深度优先搜索(为什么呢?string除了操作慢,它占用的内存更是多,若以string为队列基本类型很容易内存超限)。又由于深度优先搜索,我们有必要判断一下重复。根据之前的经验,作者第一次想到的是map(关联式容器)。就是这样:(不懂关联式容器的同学可以看看这道题:map专练-统计数字)
map<string,bool> ma;
但是这个想法马上被否认了,因为作者发现题目中规定一个单词只能用2次,一个更简便的方法是用数组。由于我们是按顺序输入的,我们可以用它的编号代替它使用的次数。
为了模拟接龙的过程,函数的形参为:string L。
接下来我们开始写函数。首先是一个保存答案的操作,我们需要更新答案的最大值。然后遍历所有的单词,若还可以使用(使用次数<2),则进入。注意此时不要判断是否能够前后相接,因为若两个串存在重合的一部分,则我们无法直接判断。当我们进入后,通过取子串的方式,可以判断是否能够相接。若可以,要注意不要直接相接,要将重合的部分排除掉再相接(相接可以直接用string的“+”)。最后别忘了回溯。
回到main函数后,我们就进行输出,下次循环的时候,别忘了初始化答案和单词的使用次数。
题外话
各位同学曾为流输入输出速度慢而烦恼吗?我们可以调用一个神奇的东西来实现流加速(我在书上看到的,也不知道为什么):
ios::sync_with_stdio(false);
也就是关闭了流输入输出和stdio的关联。其中的具体我还不知道,知道的朋友评论一下,谢谢!
程序样例
1次Accepted,感觉自己挺6的
/*Lucky_Glass*/ #include<iostream> #include<cstring> #include<iostream> using namespace std; string s[25]; int n,use[25],ans; char ch; void flag(string L) { ans=max(ans,(int)L.size()); for(int i=0;i<n;i++) if(use[i]<2) { bool Continue=true; int Size=L.size(),j; for(j=1;j<Size;j++) { string sub=L.substr(Size-j,j); char S1[1005],S2[25]; strcpy(S1,sub.c_str()); strcpy(S2,s[i].c_str()); if(strstr(S2,S1)-S2==0) { Continue=false; break; } } if(Continue) continue; use[i]++; flag(L+s[i].substr(j,s[i].size()-j)); use[i]--; } } int main() { int Ans=0; ios::sync_with_stdio(false); cin>>n; for(int i=0;i<n;i++) cin>>s[i]; cin>>ch; for(int i=0;i<n;i++) if(s[i][0]==ch) { ans=0; memset(use,false,sizeof(use)); use[i]++; flag(s[i]); Ans=max(Ans,ans); } cout<<Ans<<endl; return 0; }
相关文章推荐
- NOIP 2000 提高组 复赛 单词接龙
- 竞赛题目讲解-【NOIP2000提高组】乘积最大
- 【NOIP2000】单词接龙
- NOIP2000提高组 单词接龙
- 【DFS】CODE[VS] 1018&&NOIP2000提高组T3 单词接龙 (日常刷题???)
- NOIP2000单词接龙[DFS]
- 05:统计单词数【NOIP2011复赛普及组第二题】
- [NOIP提高组2000]单词接龙
- NOIP 2000年提高组复赛 单词接龙
- [NOIP2000]单词接龙
- noip2000-单词接龙2008.11.5
- NOIP 2011 普及组 复赛 stat 统计单词数
- 【用膝盖写代码系列】(2):NOIP2011普及组复赛题目详解
- HRBUST 1213 单词接龙 NOIP2000
- Codevs 1018 单词接龙 DFS --2000年NOIP全国联赛普及组NOIP全国联赛提高组
- noip2000单词接龙解题报告
- 【C++心路历程32】【NOIP2000】单词接龙【图论爆搜最长链】
- NOIP 2000 单词接龙
- ◆竞赛题目◆◇NOIP2015普及组◇求和
- 深度优先搜索 之 CODE[VS] 1018 单词接龙 2000年NOIP全国联赛普及组NOIP全国联赛提高组