题目连接:
https://www.luogu.org/problem/P1019c++
题目大意:
①已知一组单词,且给定一个开头的字母,要求出以这个字母开头的最长的“龙”
②每一个单词都最多在“龙”中出现两次
③重合部分合为一部分,且每次取两单词重合部分的最短值
④两单词不能有包含关系web
个人题解:
以给出的输入输出样例为例:数组
输入: 5 at touch cheat choose tact a
输出: 23
①首先对要判断的两个字符串进行判断,获得两个字符串链接后,第二个字符串减去重合部分的长度(如at和touch处理后获得4,而at和at处理后为0),由此获得表格:
svg
获得该表格以后就可用DFS深搜一个一个试哪条龙是最长的了spa
按样例的数据解题过程就是:code
个人代码:xml
#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); }