题解 P2322 [HNOI2006]最短母串问题
ACAM 和状压 dp 的做法
题意
给定 $n$ 个字符串 $s_1,s_2,s_3...s_n$,对于字符串 $T$,满足 $\forall i\in\left[1,n\right]$,$s_i$ 为 $T$ 的子串,求 $|T|$ 最小时的 $T$。
数据范围: $1\le n\le12,1\le s_i\le50$
做法
显然是个多模匹配问题,考虑 ACAM。
若使 $T$ 匹配到所有字符串,说明该 $T$ 在 Trie 图上包含了所有字符串的结束节点。又因为每个节点到根的路径上可能会包含很多个字符串,所以状态压缩存每个节点到跟的路径上包含的字符串,对于节点 $i$,记 $sta_i$ 存该点路径上包含的字符串,令 $2^{i-1}$ 表示 $s_i$,即用二进制表示。若 $s_i$ 结束的节点为 $p$,则 $sta_p\gets sta_p\operatorname{or} 2^{i-1}$,即 $sta_p$ 加入字符串 $s_i$。在构建 $fail$ 树的时候再顺着 $fail$ 边加入所有后缀的状态。
在寻找 $\min |T|$ 时,从根节点按字典序 BFS,记录当前状态 $now$,顺着 Trie 树,每到一个节点 $x$,令 $now\gets now \operatorname{or}sta_x$,并用 $pre_x$ 指针记录该次 BFS 时间,直到 $now=2^n-1$,即每个字符串都在该串中,又因为是 BFS,该串长度最小,即为答案,利用 $pre$ 指针输出即可。
时间复杂度 $O(2^n\sum |s_i|)$。
#include <bits/stdc++.h>
#define pii pair<int, int>
using namespace std;
const int N = 6e2 + 10, M = 1 << 12 | 1, S = 26;
int n, ans[N * M], tot, pre[N * M];
char s[N];
bool vis[N][M];
namespace AC_Automaton {
int ch[N][S], fail[N], sta[N], cnt;
void insert(char *s, int d) {
int len = strlen(s + 1), x = 0;
for(int i = 1; i <= len; i++) {
if(!ch[x][s[i] - 'A']) ch[x][s[i] - 'A'] = ++cnt;
x = ch[x][s[i] - 'A'];
}
sta[x] |= (1 << (d - 1));
}
void getfail() {
queue<int> q;
for(int i = 0; i < S; i++) if(ch[0][i]) q.push(ch[0][i]);
while(!q.empty()) {
int u = q.front();
q.pop();
for(int i = 0; i < S; i++)
if(ch[u][i]) fail[ch[u][i]] = ch[fail[u]][i], sta[ch[u][i]] |= sta[ch[fail[u]][i]], q.push(ch[u][i]);
else ch[u][i] = ch[fail[u]][i];
}
}
} using namespace AC_Automaton;
queue<pii> q;
int main() {
scanf("%d", &n);
for(int i = 1; i <= n; i++) {
scanf("%s", s + 1);
insert(s, i);
}
getfail();
q.push({0, 0});
vis[0][0] = 1;//vis判重,第一维表示节点,第二维表示状态
int now = 0;
while(!q.empty()) {
int x = q.front().first, st = q.front().second;
q.pop();
if(st == (1 << n) - 1) {
int len = 0;
while(now) {
s[++len] = ans[now] + 'A';
now = pre[now];
}
for(int i = len; i; i--) putchar(s[i]);
break;
}
for(int i = 0, v; i < S; i++) {
v = ch[x][i];
if(!vis[v][st | sta[v]]) {
vis[v][st | sta[v]] = 1;
q.push({v, st | sta[v]});
pre[++tot] = now, ans[tot] = i;
}
}
now++;
}
return 0;
}

浙公网安备 33010602011771号