题目描述
单词接龙是一个与我们经常玩的成语接龙相类似的游戏,现在我们已知一组单词,且给定一个开头的字母,要求出以这个字母开头的最长的“龙”(每个单词都最多在“龙”中出现两次),在两个单词相连时,其重合部分合为一部分,例如 beast和astonish,如果接成一条龙则变为beastonish,另外相邻的两部分不能存在包含关系,例如at 和 atide 间不能相连。
输入输出格式
输入格式:输入的第一行为一个单独的整数n (n<=20)表示单词数,以下n 行每行有一个单词,输入的最后一行为一个单个字符,表示“龙”开头的字母。你可以假定以此字母开头的“龙”一定存在.
输出格式:只需输出以此字母开头的最长的“龙”的长度
重点:单词重叠的部分不好操作
在搜索的基础上代码需要有所修改。
首先,题目包含的接龙要求大致有以下几点:1.同一个单词最多出现2次 2.相邻的两部分不能存在包含关系 3.在两个单词相连时,其重合部分合为一部分。
我们很容易就可以想到,使用一个结构体用于存储各个单词的数据,包括单词本身,它的实际长度以及可供使用的剩余次数(初始值为2).如下:
struct words
{
int left = 2, tail = 0; //剩余的使用次数 单词实际长度
char word[101]; //内容
}words[22];
我们可以使用一个字符变量start用来存储开头的字母,然后即可开始搜索,由于start当中的字符并不会被计入总长度,所以可以先通过一个循环,找到符合题意的单词,然后再以这个单词作为开头,进行深搜。
cin >> start;
for (int i = 0; i < wordTot; i++)
if (words[i].word[0] == start)
{
words[i].left--;
dfs(words[i].word, words[i].tail); //目前龙中最后一个单词 长度
words[i].left++;
}
由于单词接龙中相邻的两部分不能存在包含关系,所以无论龙有多长,只需要考虑最后一个加入的单词能够和那些单词拼接即可。在这里,我们可以编写一个函数juj来判断两个单词之间重合部分长度的最小值。
int juj(char a[], char b[])
{
int al = strlen(a), bl = strlen(b), j;
bool flag = true;
for (int i = 1; i < al && i < bl; i++)
{
flag = true;
for (j = 0; j < i; j++)
if (a[al - i + j] != b[j]) { flag = false; break; }
if (flag)
return i;
}
return 0;
}
这个函数主要的原理是:在a,b两个字符串当中一个个地尝试可能重合部分的长度,并把这个长度作为一个数值返回。如果这个长度已经不小于当中最短字符串的长度,那么说明这两个字符串没有符合题意的重合部分,juj将返回0。
处理好了单词重合部分,剩下的就是搜索了。这部分比较简单,直接照着深搜的伪代码模板进行填充相应的代码即可。
void dfs(char tail[], int num)
{
_max = max(_max, num); //更新最大值
int a; //两个单词重合部分的长度
for (int i = 0; i < wordTot; i++)
if (words[i].left > 0)
{
a = juj(tail, words[i].word);
if (a != 0) //判断是否符合题意
{
words[i].left--;
dfs(words[i].word, num + words[i].tail - a); //下一步搜索
words[i].left++;
}
}
}
这样,程序就基本完成了,下面是完整的代码:
#include<iostream>
#include<cstring>
#include<algorithm>
using namespace std;
int wordTot, _max = 0;
struct words
{
int left = 2, tail = 0; //剩余的使用次数 单词实际长度
char word[101]; //内容
}words[22];
int juj(char a[], char b[])
{
int al = strlen(a), bl = strlen(b), j;
bool flag = true;
for (int i = 1; i < al && i < bl; i++)
{
flag = true;
for (j = 0; j < i; j++)
if (a[al - i + j] != b[j]) { flag = false; break; }
if (flag)
return i;
}
return 0;
}
void dfs(char tail[], int num)
{
_max = max(_max, num); //更新最大值
int a; //两个单词重合部分的长度
for (int i = 0; i < wordTot; i++)
if (words[i].left > 0)
{
a = juj(tail, words[i].word);
if (a != 0) //判断是否符合题意
{
words[i].left--;
dfs(words[i].word, num + words[i].tail - a); //下一步搜索
words[i].left++;
}
}
}
int main()
{
char start;
cin >> wordTot;
for (int i = 0; i < wordTot; i++)
{
cin >> words[i].word;
words[i].tail = strlen(words[i].word);
}
cin >> start;
for (int i = 0; i < wordTot; i++)
if (words[i].word[0] == start)
{
words[i].left--;
dfs(words[i].word, words[i].tail); //目前龙中最后一个单词 长度
words[i].left++;
}
cout << _max << endl;
return 0;
}