【题解】单词接龙(DFS)
题目描述
单词接龙是一个与我们经常玩的成语接龙相类似的游戏,现在我们已知一组单词
且给定一个开头的字母,要求出以这个字母开头的最长的“龙”(每个单词都最多在“龙”中出现两次)
在两个单词相连时,其重合部分合为一部分,例如beast和astonish,如果接成一条龙则变为beastonish
另外相邻的两部分不能存在包含关系,例如at和atide间不能相连。
输入
输入的第一行为一个单独的整数n(n≤20)表示单词数
以下n行每行有一个单词(只含有大写或小写字母,长度不超过20)
输入的最后一行为一个单个字符,表示“龙”开头的字母。
你可以假定以此字母开头的“龙”一定存在。
输出
只需输出以此字母开头的最长的“龙”的长度。
样例
输入
5
at
touch
cheat
choose
tact
a
输出
23
样例解释
连成的“龙”为 atoucheatactactouchoose
分析及代码实现
大致步骤
- 输入
- 从开始的字符判断有没有能接到的龙
- 如果有字符串能接到,则接上去
- 算出接龙后的长度
- 找到所有接龙情况中的最大值
C++代码实现
#include
#include
#include
using namespace std;
int n, length = 0, vis[1000] = {0};
string str[1000];
//返回a,b之中可以首尾相接的长度(长度越短,相接后的字符串越长)
//此处有两个特判
//一种是没有重合长度,要返回0
//另一种是两个字符串中长度最小的长度为1,会直接返回0
inline int check(string a, string b){
int p = min(a.length(), b.length());
for (int i = 1; a.length() == 1 ? i <= p : i < p; i++){
bool flag = true;
for (int j = 0; j < i; j++)
if (a[a.length() - i + j] != b[j]){
flag = false;
break;
}
if (flag == true) return i;
}
return 0;
}
//用dfs从1到n判断这些字符串能不能接上去
//(只要看两个字符串有没有重叠部分就可以了)
void dfs(string s, int length_now){
length = max(length, length_now);// 算出所有接龙情况中的最长长度
for (int i = 1; i <= n; i++){
if (vis[i] > 1) continue;
else{
int add = check(s, str[i]);
if (add != 0){
vis[i]++;
//接龙长度 = 龙的长度 + 现在接上的长度 - 重合的长度
dfs(str[i], length_now + str[i].length() - add);
vis[i]--;//恢复现场
}
}
}
}
int main()
{
cin >> n;
for (int i = 1; i <= n; i++) cin >> str[i];
cin >> str[n + 1];//“龙头”
dfs(str[n + 1], 1);
cout << length << endl;
return 0;
}