首先,去除一些没有用的串。
也就是说,如果存在两个串
si
和
sj
使
sj
是
si
的子串,那么需要去除掉
sj
(因为包含串
si
就一定包含串
sj
)。但是要注意考虑特殊情况:如果存在一个字符串集合
S
,
然后预处理出
DP模型:
f[S][i]
表示已经选的字符串集合为
S
,最后一个串为
代码(微恶心):
#include <cmath>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
const int N = 14, M = 53, R = 605, C = (1 << 12) + 5, INF = 0x3f3f3f3f;
int n, nxt[M], len[N], tmp[N], f[C][N], con[N][N];
char s[N][M], ts[N][M];
bool vis[N]; string st[N][M], str[C][N];
bool check(int x, int y) {
int i, j = 0; nxt[1] = 0;
for (i = 2; i <= len[y]; i++) {
while (j && s[y][i] != s[y][j + 1]) j = nxt[j];
if (s[y][i] == s[y][j + 1]) j++;
nxt[i] = j;
}
j = 0; for (i = 1; i <= len[x]; i++) {
while (j && s[x][i] != s[y][j + 1]) j = nxt[j];
if (s[x][i] == s[y][j + 1]) j++;
if (j == len[y]) return 1;
}
return 0;
}
bool check2(int x, int y, int p) {
int i; for (i = len[x] - p + 1; i <= len[x]; i++)
if (s[x][i] != s[y][i + p - len[x]]) return 0;
return 1;
}
void DP() {
int i, j, k, Cm = 1 << n; for (i = 1; i < Cm; i++)
for (j = 1; j <= n; j++) {
if (!((i >> j - 1) & 1)) continue;
if (!(i & (i - 1))) {
f[i][j] = len[j]; str[i][j] = st[j][1];
continue;
}
f[i][j] = INF; string tm(600, 'Z'); str[i][j] = tm;
for (k = 1; k <= n; k++) {
if ((!((i >> k - 1) & 1)) || j == k) continue;
int S = i ^ (1 << j - 1), le = f[S][k] + len[j] - con[k][j];
if (le < f[i][j] || (le == f[i][j] &&
(str[S][k] + st[j][con[k][j] + 1]) < str[i][j]))
f[i][j] = le, str[i][j] =
str[S][k] + st[j][con[k][j] + 1];
}
}
int res = INF; string zz(600, 'Z');
for (i = 1; i <= n; i++)
if (f[Cm - 1][i] < res || (f[Cm - 1][i] == res &&
str[Cm - 1][i] < zz)) res = f[Cm - 1][i], zz = str[Cm - 1][i];
cout << zz << endl;
}
int main() {
int i, j, k, tot = 0; scanf("%d", &n);
for (i = 1; i <= n; i++) scanf("%s", s[i] + 1), len[i] = strlen(s[i] + 1);
for (i = 1; i <= n; i++) for (j = 1; j <= n; j++) {
if (i == j) continue;
if (check(i, j) && (len[i] != len[j] || (len[i] == len[j] && i < j)))
vis[j] = 1;
}
for (i = 1; i <= n; i++) {
if (vis[i]) continue; tot++;
for (j = 1; j <= len[i]; j++) ts[tot][j] = s[i][j];
tmp[tot] = len[i];
}
n = tot; for (i = 1; i <= n; i++) {
for (j = 1; j <= tmp[i]; j++) s[i][j] = ts[i][j];
len[i] = tmp[i];
}
for (i = 1; i <= n; i++) for (j = 1; j <= n; j++)
for (k = 1; k < min(len[i], len[j]); k++)
if (check2(i, j, k)) con[i][j] = k;
for (i = 1; i <= n; i++) for (j = 1; j <= len[i]; j++) {
string tm(len[i] - j + 1, 'A');
for (k = j; k <= len[i]; k++) tm[k - j] = s[i][k];
st[i][j] = tm;
}
return DP(), 0;
}
此外,此题的AC自动机解法参考链接:http://wyfcyx.is-programmer.com/posts/76627.html。