【洛谷】P1019 单词接龙(dfs+字符串)题解

原题链接:https://www.luogu.org/problem/P1019

题目描述

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

输入输出格式

输入格式:

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

输出格式:

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

输入输出样例

输入样例#1:

5
at
touch
cheat
choose
tact
a

输出样例#1:

23

说明

时空限制:1000ms 125M

(连成的“龙”为atoucheatactactouchoose)

NOIp2000提高组第三题

思路:
1、一道dfs+字符串的题目。

2、先用数组used[i]把所有单词初始化为0,表示所有单词均未使用过。然后从给定的字符头进行深搜,遍历每个单词,先判断该单词使用次数是否已满两次,再通过自定义check函数判断该单词是否符合条件能拼接上,如果可以则调用自定义split函数拼接单词。然后判断长度改变,是的话可以连接,继续深搜,否则回溯,具体见代码注释。


代码如下:

#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
using namespace std; 
int n;	//单词数 
int ans=0; //最长的"龙"的长度
int used[25];	//表示单词用过的次数 
string word[25],start;	//表示单词和开头的字母 
bool check(string str3,string str4,int t)	//检查两个单词是否符合拼接条件 
{
	int len3=str3.length();	//前面单词长度 
	for(int i=0;i<t;i++)	//遍历接口长度 
	{
		if(str3[len3+i-t]!=str4[i])	//如果后面单词前缀与前面单词后缀不同 
			return false;	//返回false 
	}
	return true;	//如果后面单词前缀与前面单词后缀相同,返回true 
}
void split(string &str3,string str4,int t)	//拼接 
{
	int len4=str4.length();	//后面单词长度 
	for(int i=t;i<len4;i++)	//把后面单词重合部分忽略掉,拼接不重合部分 
		str3+=str4[i];
}
void dfs(string str1)	//深搜 
{
	int len1=str1.length();	//拼接的前面单词长度 
	ans=max(len1,ans);	//每次拼接之后取最大值 
	for(int i=0;i<n;i++)
	{
		if(used[i]>=2)	//每个单词最多使用两次 
			continue;
		else	//如果单词未使用满两次 
		{
			int len2=word[i].length();	//拼接的后面单词长度 
			for(int j=1;j<=len2;j++)	//枚举后面单词作为接口的长度 
			{
				if(check(str1,word[i],j))	//如果符合拼接条件拼接 
				{
					string str2=str1;	//把前面单词暂存进str2 
					split(str2,word[i],j);	//拼接 
					if(str2==str1)	//如果拼接之后长度没改变,说明两个单词包含关系
						continue;	//剪掉 
					used[i]++;	//单词使用次数+1 
					dfs(str2);	//继续深搜 
					used[i]--;	//回溯 
				}
			}
		}
	}
}
int main() 
{
	memset(used,0,sizeof(used));	//表示单词均未用过 
	scanf("%d",&n);
	for(int i=0;i<n;i++)	//输入单词 
		cin>>word[i];
	cin>>start;	//输入开头的字母 
	dfs(start);	//从开头的字母开始深搜 
	printf("%d\n",ans); //输出"龙"的长度 
	return 0;
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值