P1019 [NOIP2000 提高组] 单词接龙—解题报告

一、题目链接

P1019 [NOIP2000 提高组] 单词接龙

二、题目大意

给出 n n n个单词,并给出一个字符作为“头”,要求求出以“头”作为起始字符能够拼接出的字符串的最大长度,每一个单词最多使用两次。两个单词能够拼接当且仅当单词①的前缀等于单词②的后缀,则最后两个相同部分和为一个。

  • b e a s t beast beast a s t o n i s h astonish astonish,如果接成一条龙则变为 b e a s t o n i s h beastonish beastonish
  • 另外相邻的两部分不能存在包含关系,例如 a t at at a t i d e atide atide间不能相连(相连也没有意义)。

数据范围: 1 ≤ n ≤ 20 1\leq n\leq 20 1n20,单词长度未给出,但不超过 10000 10000 10000

三、题目分析

因为涉及到两个单词的前后缀匹配问题,为了防止每次都去暴力寻找两个单词前后缀的匹配情况,我们可以先预处理(暴力匹配)出每两个单词的前后缀能够匹配的最大长度:

int getans(int fir,int sec)//暴力匹配fir的后缀和sec的前缀,得到最大的匹配长度
{
	int Link=Max;
	for(int i=1;i<len[fir];i++)
	{
		int flag=0;
		if(len[fir]-i-1>=len[sec])
			continue;
		for(int j=0;j<=len[fir]-i-1;j++)
		{
			if(s[fir][i+j]!=s[sec][j])
			{
				flag=1;
				break;
			}
		}
		if(!flag)
			Link=len[fir]-i;
	}
	return Link;
}
for(int i=0;i<n;i++)
	for(int j=0;j<n;j++)
		match[i][j]=getans(i,j);

因为数据范围很小,只有 n ≤ 20 n\leq20 n20,所以预处理结束之后我们就可以利用预处理出的结果进行搜索。因为没有明显的分层情况,无法使用 D P DP DP来求解,所以只能使用 D F S DFS DFS。如果出现一个单词没有别的单词的前缀能与之匹配,则代表到了搜索终点,记录答案的最大值即可。

四、正解程序

#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cmath>
#define Max 0x7ffffff

using namespace std;
typedef long long ll;

int n,match[50][50],times[50],len[50];
char s[50][10010];
int ans;

int getans(int fir,int sec)//暴力匹配
{
	int Link=Max;
	for(int i=1;i<len[fir];i++)
	{
		int flag=0;
		if(len[fir]-i-1>=len[sec])
			continue;
		for(int j=0;j<=len[fir]-i-1;j++)
		{
			if(s[fir][i+j]!=s[sec][j])
			{
				flag=1;
				break;
			}
		}
		if(!flag)
			Link=len[fir]-i;
	}
	return Link;
}
void dfs(int k,int temp)//搜索
{
	if(temp>ans)
		ans=temp;
	for(int i=0;i<n;i++)
	{
		if(times[i]<2 && match[k][i]!=Max)//能够匹配,且使用次数不超过两次
		{
			times[i]++;
			dfs(i,temp+len[i]-match[k][i]);
			times[i]--;
		}
	}
}
int main()
{
	cin>>n;
	for(int i=0;i<n;i++)
	{
		cin>>s[i];
		len[i]=strlen(s[i]);
	}
	char Mark;
	cin>>Mark;
    memset(times,0,sizeof(times));
	for(int i=0;i<n;i++)//求出第i个单词的后缀和第j个单词的前缀的最大匹配长度,如果不能匹配,则置为Max
		for(int j=0;j<n;j++)
			match[i][j]=getans(i,j);
	for(int i=0;i<n;i++)
	{
		if(s[i][0]==Mark)//找到一个前缀为题目给定的头的单词作为搜索起点
		{
			times[i]++;
			dfs(i,len[i]);
			times[i]--;
		}
	}
	printf("%d",ans);
	
	return 0;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值