【搜索】 noi openjudge 2.5 单词接龙

本文介绍了一种解决单词接龙问题的算法实现,通过深度优先搜索策略来寻找以特定字母开头的最长单词序列,同时确保序列中相邻单词不构成包含关系。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

8783:单词接龙


总时间限制: 
1000ms 
内存限制: 
65536kB
描述

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

输入
输入的第一行为一个单独的整数n(n<=20)表示单词数,以下n行每行有一个单词(只含有大写或小写字母,长度不超过20),输入的最后一行为一个单个字符,表示“龙”开头的字母。你可以假定以此字母开头的“龙”一定存在。
输出
只需输出以此字母开头的最长的“龙”的长度。
样例输入
5
at
touch
cheat
choose
tact
a
样例输出
23
提示
连成的“龙”为atoucheatactactouchoose


分析:
看到题的第一眼我的反应时“我的天做得出来才有鬼”
然后我仔细看了看题,发现范围不大
既然如此,那么就用深搜把每个可能的匹配枚举出来
需要注意的是2个点:
一是如何连接单词,二是每个单词可以用两次
连接的时候一个字母一个字母地比对
单词用两次的话可以把输入复制一遍,然后n*2

代码加注释:
#include<cstdio>
#include<cstring>
char a[23][23];
int n,sum;
bool vis[23];
bool lian(char a[],char b[])
{
	int la=strlen(a),lb=strlen(b),i,j,p;
	for(i=lb-1;i>0&&i>lb-la;i--)
		if(b[i]==a[0])
		{
			for(j=i+1;j<lb;j++)
				if(b[j]!=a[j-i]) goto he;
			for(j=lb,p=lb-i;p<la;p++,j++)
				b[j]=a[p];//连接
			return 1;
		he:;
		}
		return 0;//不能连接
}
void xmy(int s,char k[])
{
	char o[410];
	for(int j=0;j<n;j++)
		if(!vis[j])
		{
			memset(o,0,sizeof(o));//之所以要用o数组是因为函数调用的时候数组传的是地址
											//也就是说后面的改动会影响k的值,因为它们对应同一地址
			strcpy(o,k);
			if(lian(a[j],o)) {vis[j]=1;xmy(strlen(o),o);vis[j]=0;}
			else if(j%2==0) j++;//如果当前的这个单词不能连接,那么它所复制的单词也不能连接,这是优化
				//if(j%2==0)非常重要,因为如果当前单词已经是复制出来的就不用加了,当初我没写。。。。卡了老半天
		}
	if(s>sum) sum=s;
}
int main()
{
	scanf("%d",&n);n*=2;
	for(int i=0;i<n;i+=2)
	{
		scanf("%s",a[i]);
		strcpy(a[i+1],a[i]);//复制一遍
	}
	char k[1];
	scanf("%s",k);
	for(int i=0;i<n;i+=2)//+2,因为同一个单词拓展出的是一样的
		if(k[0]==a[i][0]) {vis[i]=1;xmy(strlen(a[i]),a[i]);vis[i]=0;}
	printf("%d",sum);
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值