题目链接:
https://www.luogu.org/problem/P1019
题目大意:
①已知一组单词,且给定一个开头的字母,要求出以这个字母开头的最长的“龙”
②每个单词都最多在“龙”中出现两次
③重合部分合为一部分,且每次取两单词重合部分的最短值
④两单词不能有包含关系
我的题解:
以给出的输入输出样例为例:
输入:
5
at
touch
cheat
choose
tact
a
输出:
23
①首先对要判断的两个字符串进行判断,得到两个字符串连接后,第二个字符串减去重合部分的长度(如at和touch处理后得到4,而at和at处理后为0),由此得到表格:
得到该表格之后就可用DFS深搜一个一个试哪条龙是最长的了
按样例的数据解题过程就是:
我的代码:
#include<bits/stdc++.h>
using namespace std;
string s[50];
char ch;
int cd[50][50]; //cd数组用来记录第二个单词除去重叠部分的值
int vis[50]; //记录每个单词使用次数
int ans, tmp, n;
void count(int a, int b){
int alen = s[a].length();
int blen = s[b].length();
int flag; //flag记录第一个字符串末尾和第二个字符串开头是否有重叠部分
int i;
for(int j=0; j<alen; j++){
flag = 1;
for(i=0; i+j<alen&&i<blen; i++){
if(s[a][i+j] != s[b][i]){
flag = 0;
break;
}
}
//如果有重叠部分,cd数组记录第二个字符串减去重叠部分的值
if(flag)
cd[a][b] = blen-i;
}
}
int dfs(int pos){
//flag变量记录位置为pos的单词是否还能接下一个单词
int flag = 1;
for(int i=0; i<n; i++){
if( vis[i]==2 || cd[pos][i]==0 ) continue;
vis[i]++;
tmp+=cd[pos][i];
flag = 0;
dfs(i);
tmp-=cd[pos][i];
vis[i]--;
}
//如果单词接龙已经结束,记录下长度最大值
if(flag)
ans = max(ans, tmp);
}
int main(){
scanf("%d", &n);
for(int i=0; i<n; i++){
cin>>s[i];
}
cin>>ch;
//初始化cd数组
for(int i=0; i<n; i++){
for(int j=0; j<n;j ++){
count(i, j);
}
}
ans = tmp = 0;
for(int i=0; i<n; i++){
if(s[i][0] == ch){
vis[i]++;
tmp = s[i].length();
dfs(i);
vis[i]--;
}
}
printf("%d\n",ans);
}