图论方法
如果字符串a, b之间有公共长度len,则可以看成a向b连一条长度为len的边。依照此想法,原问题就是求以一个点开始(某个字母为开头单词),每个点最多经过不超过两次,可以到达的最远路径长度。
因此,有了以下代码:
#include <iostream>
#include <cstring>
using namespace std;
const int N = 25, M = 1010;
string wd[N], st;
int h[N], e[M], ne[M], w[M], idx, cnt[N];
void add(int a, int b, int c) {
e[idx] = b, ne[idx] = h[a], w[idx] = c, h[a] = idx++;
}
int get(int i, int j) {
string a = wd[i], b = wd[j];
for (int i = a.size() - 1; i > 0; i--) {
int l = a.size() - i;
if (l <= b.length() && a.substr(i, l) == b.substr(0, l)) return l;
}
return 0;
}
int dfs(int u) {
int res = 0;
for (int i = h[u]; ~i; i = ne[i]) {
int j = e[i];
if (cnt[j] < 2) {
cnt[j]++;
res = max(res, dfs(j) - w[i]);
cnt[j]--;
}
}
return res + wd[u].length();
}
int main() {
memset(h, -1, sizeof h);
int n;
cin >> n;
for (int i = 0; i < n; i++) cin >> wd[i];
cin >> st;
for (int i = 0; i < n; i++)
for (int j = i; j < n; j++) {
int c = get(i, j);
if (c)add(i, j, c);
c = get(j, i);
if (c && i != j)add(j, i, c);
}
int res = 0;
for (int i = 0; i < n; i++) {
if (wd[i][0] == st[0]) {
memset(cnt, 0, sizeof cnt);
cnt[i] = 1;
res = max(res, dfs(i));
}
}
cout << res << endl;
return 0;
}