题目描述
单词接龙是一个与我们经常玩的成语接龙相类似的游戏,现在我们已知一组单词,且给定一个开头的字母,要求出以这个字母开头的最长的“龙”(每个单词都最多在“龙”中出现两次),在两个单词相连时,其重合部分合为一部分,例如beast和astonish,如果接成一条龙则变为beastonish,另外相邻的两部分不能存在包含关系,例如at和atide间不能相连。
输入格式
输入的第一行为一个单独的整数n表示单词数,以下n行每行有一个单词,输入的最后一行为一个单个字符,表示“龙”开头的字母。你可以假定以此字母开头的“龙”一定存在.
输出格式
只需输出以此字母开头的最长的“龙”的长度
数据范围
n ≤ 20
输入输出样例
输入
5
at
touch
cheat
choose
tact
a
输出
23
深搜,明确要让接起来的龙最长。
▶需要考虑一种特殊情况,当两个单词的重叠部分出现了不止一次,为了使接起来的龙最长,应取最小的重叠长度。比如,假设一个单词是okokok,另一个单词是okoking,此时重叠长度应取2,即“ok”,接龙总长度为11,即“okokokoking”,若重叠长度取4即“okok”,总长度会缩短成 9 即“okokoking”
▶考虑到以上情况,当在两个单词间找到最小重叠长度时要停止比较(代码第 16 行)
▶根据给定的开头字母,选取拥有相同字母开头的单词开始搜索(代码 33~37 行)
▶查找两个单词间是否有重叠部分(代码12~17行)
#include
#include
using namespace std;
string s[20];
char st; //开头字母
int n, len = 0, rem[20]; //单词数,接龙长度,单词剩余使用次数
void dfs(string str, int nowlen){
len = max(len, nowlen);
for(int i = 0; i < n; i++){
if(!rem[i]) continue;
int rp = 0; //重叠长度
for(int p = 1; p < min(str.length(), s[i].length()); p++){
bool flag = true; //作为有否找到重叠部分的标志
for(int q = 0; q < p; q++)
if(str[str.length()-p+q] != s[i][q]) flag = false;
if(flag) {rp = p; break;} //找到最小重叠长度就跳出循环
}
if(rp){ //如果可以接龙
rem[i]--; //当前龙尾单词剩余使用次数-1
dfs(s[i], nowlen+s[i].length()-rp); //继续接龙
rem[i]++;
}
}
}
int main()
{
cin >> n;
for(int i = 0; i < n; i++){
cin >> s[i];
rem[i] = 2; //每个单词可用2次
}
cin >> st; //开头字符
for(int i = 0; i < n; i++)
if(s[i][0] == st){
rem[i]--;
dfs(s[i], s[i].length());
}
cout << len << endl;
return 0;
}