洛谷 [P1019 单词接龙] {搜索|DFS} 奋斗的珂珂~

题目描述

单词接龙是一个与我们经常玩的成语接龙相类似的游戏,现在我们已知一组单词,且给定一个开头的字母,要求出以这个字母开头的最长的“龙”(每个单词都最多在“龙”中出现两次),在两个单词相连时,其重合部分合为一部分,例如 beast和astonish,如果接成一条龙则变为beastonish,另外相邻的两部分不能存在包含关系,例如atat 和 atide 间不能相连。

输入格式

输入的第一行为一个单独的整数n (n≤20)表示单词数,以下nn 行每行有一个单词,输入的最后一行为一个单个字符,表示“龙”开头的字母。你可以假定以此字母开头的“龙”一定存在.

输出格式

只需输出以此字母开头的最长的“龙”的长度

输入输出样例

输入
5
at
touch
cheat
choose
tact
a
输出
23

说明/提示

(连成的“龙”为atoucheatactactouchoose)

NOIp2000提高组第三题

完整代码

#include
using namespace std;
int lens[30][30];//lens[i][j]代表第i个字符串与第j个字符串之间最长的公共长度 
int sum[30];
char a[30][100];
int m;//代表字符串个数 
char start;//代表“龙”开始的第一个字母 
int ans;
//std::ios::sync_with_stdio(false)省略cin输入的时间 
//深度优先搜索 


int check(int x,int y)//使得y接在x的后面 
{
	int len1=strlen(a[x]);
	int len2=strlen(a[y]);
	
	for(int k=1;k<min(len1,len2);k++)//不取等于就保证了不是子集 
	{
		int i=len1-k,j=0;//从0下标开始是字符串的输入 
	    bool flag=true;
	    while(i<len1&&j<k)//输入的时候下标均是从0开始的 
		{
			if(a[x][i]!=a[y][j])//如果出现不相等,说明该k值不是他的公共长度 
			{
				flag=false;
				break;
			}
			i++,j++; //继续判断 
		 } 
		 if(flag)
		 {
		 	return k;//返回公共长度部分 
		  } 
	}
	return 0;//没有公共长度就返回0 
}

void dfs(int index,int len)
{
	ans=max(ans,len);
	
	for(int i=1;i<=m;i++)
	{
		if(sum[i]>1) continue;//如果使用次数大于2,就直接不判断 
		if(lens[index][i]==0) continue;//如果没有公共部分,就直接不判断 
		sum[i]++;//使用次数加1 
		dfs(i,len+strlen(a[i])-lens[index][i]);
		sum[i]--;//恢复状态 
	 } 
}

int main()
{
	scanf("%d",&m);
	std::ios::sync_with_stdio(false);
	for(int i=1;i<=m;i++)
	{
		cin>>a[i];
	 } 
	cin>>start;//!!!不用%c因为之前可能有好多回车,使用cin忽略所有回车 
	
	for(int i=1;i<=m;i++)
	{
		for(int j=1;j<=m;j++)
		{
			lens[i][j]=check(i,j);
		}
	 } 
	 
	 for(int i=1;i<=m;i++)
	 {
	 	if(a[i][0]==start)//如果首字母等于给出的字母,就进行深度优先搜索 
	 	{
	 		sum[i]++;
	 		dfs(i,strlen(a[i]));
	 		sum[i]--;
		 }
	 }
	 printf("%d\n",ans);
	 return 0;
}
 


你可能感兴趣的:(DFS,搜索)