洛谷 普及组 P1019 单词接龙

题目描述

单词接龙是一个与我们经常玩的成语接龙相类似的游戏,现在我们已知一组单词,且给定一个开头的字母,要求出以这个字母开头的最长的“龙”(每个单词都最多在“龙”中出现两次),在两个单词相连时,其重合部分合为一部分,例如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;
}

 

 

你可能感兴趣的:(洛谷刷题日记)