您的位置:首页 > 编程语言 > C语言/C++

竞赛题目讲解-【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种选择:字符串stringchar数组,两种方法都可以解出题目。但是,作者在这里推荐使用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;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  C++ Openjudge 算法竞赛