🏆今日学习目标:
🍀学习了解P1019 [NOIP2000 提高组]单词接龙--题目详解
✅创作者:贤鱼
⏰预计时间:15分钟
@TOC
题目要求
[NOIP2000 提高组] 单词接龙
题目背景
注意:本题为上古 NOIP 原题,不保证存在靠谱的做法能通过该数据范围下的所有数据。
题目描述
单词接龙是一个与我们经常玩的成语接龙相类似的游戏,现在我们已知一组单词,且给定一个开头的字母,要求出以这个字母开头的最长的“龙”(每个单词都最多在“龙”中出现两次),在两个单词相连时,其重合部分合为一部分,例如 beast
和 astonish
,如果接成一条龙则变为 beastonish
,另外相邻的两部分不能存在包含关系,例如 at
和 atide
间不能相连。
输入格式
输入的第一行为一个单独的整数 $n$ 表示单词数,以下 $n$ 行每行有一个单词,输入的最后一行为一个单个字符,表示“龙”开头的字母。你可以假定以此字母开头的“龙”一定存在。
输出格式
只需输出以此字母开头的最长的“龙”的长度。
样例 #1
样例输入 #1
5
at
touch
cheat
choose
tact
a
样例输出 #1
23
提示
样例解释:连成的“龙”为 atoucheatactactouchoose
。
$n \le 20$。
思路
==典型深搜问题==
想到深搜不难,问题是怎么搜?
很简单
在搜索的时候,判断两个单词的重叠部分,符合题意就继续搜索,反正时间复杂度不会爆炸其他的就是电脑的任务了
问题是如何判断两个单词的重叠部分
这里我们传两个string类型的字符串a,b
i从0到ab长度较小的一个-1的位置,j从0-i-1的位置
我们只需要从a[-i+j]和b[j]来比较
如果有重合的部分,此时的i就是重合的数量
接下来就搜索就好
AC代码
#include<cmath>
#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
int use[20];
int n;
string ch;
int aas=0;
string dc[20];
int xz(string a,string b){
int len=min(a.length(),b.length());
for(int i=1;i<len;i++){//按照上面思路处理
int f=1;//注意要赋值为1
for(int j=0;j<i;j++)
if(a[a.length()-i+j]!=b[j]) f=0;
if(f) return i;
}
return 0;
}
void dfs(string c,int ans){
aas=max(aas,ans);
for(int i=0;i<n;i++){
if(use[i]>=2) continue;//记录一下使用次数,为什么是等于2呢,因为0,1不就是两次了
int mm=xz(c,dc[i]);//如果有值说明有重合部分
if(mm>0){
use[i]++;
dfs(dc[i],ans-mm+dc[i].length());//注意,减去重合部分
use[i]--;
}
}
}
int main(){
cin>>n;
memset(use,0,sizeof(use));
for(int i=0;i<n;i++){
cin>>dc[i];
}
cin>>ch;
dfs(' '+ch,1);//题目要求,不能有包含关系,我们在前面加一个没有意义的字符,就可以避免这个问题
cout<<aas;
}