搜索:SDNU 1022 详细思路

SDNUOJ 1022 成语接龙

Problem - 1022 (rainng.com)(传送门)

输入数字n,然后输入n个单词,输入一个字母,求出以此字母开头最长的龙的长度

Sample Input:

5

at

touch

cheat

choose

tact

a

Sample Output:

23

先写上AC码:

#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cstring>
using namespace std;
const int N=28;
int n;//单词的个数n
string s[N];//存储输入的n个单词
int g[N][N];//标记n个单词间存在的路径
int used[N];//标记每个单词的使用次数(最多两次)
int ans=-1;//最长路径的长度
void dfs(string str,int cur)
{
	ans=max(ans,(int)str.size());
	for(int i=0;i<n;i++)
	{
		if(g[cur][i]&&used[i]<2)
		{
			used[i]++;
			dfs(str+s[i].substr(g[cur][i]),i);
			used[i]--;
		}
	}
}
int main()
{
	cin>>n;
	for(int i=0;i<n;i++)
	{
		cin>>s[i];
	}
	for(int i=0;i<n;i++)
	{
		for(int j=0;j<n;j++)
		{
			string a=s[i],b=s[j];
			for(int k=1;k<min(a.size(),b.size());k++)
			{
				if(a.substr(a.size()-k)==b.substr(0,k))
				{
					g[i][j]=k;
					break;
				}
			}
		}
	}
	char c;
	cin>>c;
	for(int i=0;i<n;i++)
	{
		if(s[i][0]==c)
		{
			memset(used,0,sizeof used);
			used[i]++;
			dfs(s[i],i);
		}
	}
	cout<<ans<<endl;
	return 0;
}

思路

先遍历出每个单词可以接上哪些单词,并且标记这条路径存在,然后搜索出最长的那一条。

实现

先看主函数部分

输入单词个数n和对应的n个单词(没啥好解释的):

cin>>n;
for(int i=0;i<n;i++)
{
	cin>>s[i];
}

确定存在的路径:

for(int i=0;i<n;i++)
//外层循环遍历的是路径起点
{
	for(int j=0;j<n;j++)
    //内层循环遍历的是*可能的*路径终点(所以下面要判别)
	{
		string a=s[i],b=s[j];
		for(int k=1;k<min(a.size(),b.size());k++)
        //遍历所有可能的重合字母数
		{
			if(a.substr(a.size()-k)==b.substr(0,k))
			{
				g[i][j]=k;
                //标定从第i个词可走到第j个词,重合k个字母
				break;
			}
		}
	}
}

输入龙的起始字母:

char c;
cin>>c;

寻找到最长的龙并输出其长度:

for(int i=0;i<n;i++)
{
	if(s[i][0]==c)
    //如果第i个词的头是起始字母就以之为起点找路
	{
		memset(used,0,sizeof used);
        //清零每个单词的使用次数(因为会遍历多条路径)

		used[i]++;
        //第i个单词作为起点了,所以它的使用次数先加一

		dfs(s[i],i);//寻找路径
	}
}
cout<<ans<<endl;//输出最长路径的长度
return 0;

然后看这里面的dfs函数部分:

void dfs(string str,int cur)
//联系上面,cur是单词的序号
{
	ans=max(ans,(int)str.size());
    //因为要寻找到最长的路径,所以龙尾加新词后要max一下

	for(int i=0;i<n;i++)//遍历全部可能的单词
	{
		if(g[cur][i]&&used[i]<2)
        //如果可以从第cur个词(也就是进入函数的词)到第i个词
		{
			used[i]++;//第i个词使用次数加一

			dfs(str+s[i].substr(g[cur][i]),i);
            //去以第i个单词为路径寻找下一个词

			used[i]--;
            //这一步看似反逻辑,但是是为了去寻找另外的路径
            //因为此时函数嵌套已经结束,代表着这条路已经到底了
		}
	}
}//这里用void是因为函数外已经宏定义ans了,直接操作不用return

至此,题目的思路已经很明了了。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值