【luogu】p1019 单词接龙

(碎碎念:初二的时候就开始写这道题,写了几天觉得啊好烦啊就不想写就放弃了,上初三之后终于抽出时间把这个题写完了
(搜索题要我狗命(缩成一团

题目链接:

https://www.luogu.com.cn/problem/P1019

题目描述

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

输入格式

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

输出格式

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

分析

由于题目中给出的数据范围单词数n<=20很小,可以用搜索dfs去解决

按照给出的字母,我们先确定好一个单词作为开头

枚举剩下的且使用没有超过两次的单词

对于每一个单词再枚举他的与前面单词相接位数并判断是否可行(要注意一个单词并不能完全包含在另一个单词中)。

如果他可以接在前一个单词上,

就先将它接入后增加的位数累加进最后的答案中,再去搜索下一个可以接上的单词。

边界状态:

当一个单词后无法再接入任何一个单词

我们就把答案与之前得到的最大答案进行比较取两者中最大值。

AC Code

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<string> 
using namespace std;
int read(){
	int a = 0,f = 0;char p = getchar();
	while(!isdigit(p)){f|=p=='-';p = getchar();}
	while(isdigit(p)){a = (a<<3) + (a<<1) + (p^48);p = getchar();}
	return f?-a:a;
}
char c[25][100];//存单词
int ans;//记录每一种情况的答案
int flag[10000];//标记这个单词已经用过次数 
int Ans,n; //统计最终的答案 读入单词个数
bool Flag = 0;//判断一个单词后面是否还可以继续接入单词
void dfs(int x){//dfs!
	Flag = 0;
	for(int i = 1;i <= n;i ++){//尝试把i接在x的后面
		if(flag[i] == 2)continue;
		int leni = strlen(c[i]),lenx = strlen(c[x]);//记录两个单词长度 
		int cd = min(leni,lenx)-1;//最多能接在一起的长度为两个单词长度最小值-1
		int cd1,tot;
		int jl = 1;//记录我们想要接入几位
		while(jl <= cd){
			cd1 = jl,tot = 0;
			//int now = 0;
			while(cd1){//目前判断到的位置
				if(c[x][lenx-cd1] != c[i][jl-cd1])break;
				else tot++;
				cd1--;	
			}
			if(tot == jl)break;//两个可以接在一起
			jl++;
		}
		if(tot == jl && tot != 0){//记录下来并且去搜索下一个
			//cout<<x<<" "<<i<<" "<<tot<<endl;
			Flag = 1;
			ans += (leni-jl);
			flag[i] ++;
			dfs(i);
			ans -= (leni-jl);
			flag[i] --; 
		} 
	}
	if(Flag == 0){//后面什么也没法接的时候 
	
		Ans = max(ans,Ans);
	}
}
int main(){
	n = read();
	for(int i = 1;i <= n;i++)
		scanf("%s",&c[i]);
	
	char a;
	cin >> a;
	for(int i = 1;i <= n;i++){
		if(c[i][0] == a){
			//cout<<c[i]<<endl;
			flag[i]++;
			ans = strlen(c[i]);
			dfs(i);
		}
	}
	cout << Ans;
}

注意(不过可能也就我这么憨憨才会错的一个地方)

我们在枚举他可以接入的位数时,应该从小到大进行枚举,在能让两个单词相接的情况下,让相接的部分尽可能的小

比如:
abababab和abababc

如果我们从大到小枚举它可以接入的部分那么最后相接就会变为

ababababc 有9位

但我们从小到大枚举得到的才是最长的情况

ababababababc 有13位

好了好了没了没了别看了

posted @ 2020-01-12 17:18  蕙心心w  阅读(303)  评论(0编辑  收藏  举报