题目描述
单词接龙是一个与我们经常玩的成语接龙相类似的游戏,现在我们已知一组单词,且给定一个开头的字母,要求出以这个字母开头的最长的“龙”(每个单词都最多在“龙”中出现两次),在两个单词相连时,其重合部分合为一部分,例如 beastbeastbeast和astonishastonishastonish,如果接成一条龙则变为beastonishbeastonishbeastonish,另外相邻的两部分不能存在包含关系,例如atatat 和 atideatideatide 间不能相连。
输入格式
输入的第一行为一个单独的整数nnn (n≤20n \le 20n≤20)表示单词数,以下nnn 行每行有一个单词,输入的最后一行为一个单个字符,表示“龙”开头的字母。你可以假定以此字母开头的“龙”一定存在.
输出格式
只需输出以此字母开头的最长的“龙”的长度
输入输出样例
输入 #1
5 at touch cheat choose tact a输出 #1
23说明/提示
(连成的“龙”为atoucheatactactouchoose)
NOIp2000提高组第三题
题目大意:读题吧。
解题思路:需要预处理出每两个串之间前缀和后缀的公共长度是多少,然后从龙的第一个字母开始搜就可以了。
/* @Author: Top_Spirit @Language: C++ */ #include <bits/stdc++.h> using namespace std ; typedef unsigned long long ull ; typedef long long ll ; const int Maxn = 50; const int INF = 0x3f3f3f3f ; const ull seed = 133 ; const double PI = acos(-1.0) ; int con[Maxn][Maxn] ; int vis[Maxn], ans, n ; string s[Maxn] ,op ; int check(int x, int y){ int len1 = s[x].size() ; int len2 = s[y].size() ; for (int k = 1; k <= min(len1, len2); k++){ int i = len1 - k ; int j = 0 ; bool flag = true ; while (i < len1 && j <= k){ if (s[x][i] != s[y][j]) { flag = false ; break ; } i++ ; j++ ; } if (flag) return k; } return 0 ; } void init(){ for (int i = 1; i <= n; i++){ for (int j = 1; j <= n; j++){ con[i][j] = check(i, j) ; } } } void Dfs(int index, int len){ ans = max(ans, len) ; for (int i = 1; i <= n; i++){ if (vis[i] > 1) continue ; // 每一个单词只能用两次 if (con[index][i] == 0) continue ; vis[i]++ ; Dfs(i, len + s[i].size() - con[index][i]) ; vis[i]-- ; } } int main (){ cin >> n ; for (int i = 1; i <= n; i++) cin >> s[i] ; cin >> op ; init() ; for (int i = 1; i <= n; i++){ if (s[i][0] == op[0]){ // 从龙的相同字符开始搜起 vis[i]++ ; Dfs(i, s[i].size()) ; vis[i]-- ; } } cout << ans << endl ; return 0; }