洛谷P2322 思路分享(AC 自动机,分层图最短路)
https://www.luogu.com.cn/problem/P2322
题意概述
给定 \(n\) 个字符串,找到字典序最小的最短字符串 \(T\),使得所有给定字符串都是 \(T\) 的子串.
\(1\le n \le 12\),每个字符串长度不超过 \(50\).
思路
多模式串匹配,考虑 AC 自动机.
建出 AC 自动机后,令 \(ref_u\) 为以节点 \(u\) 结尾能匹配哪些给定的字符串,用位掩码表示,注意 \(ref_u\) 是可以继承 \(ref_{fail_u}\) 的.
处理完这些,跑分层图最短路即可,记录一下前驱回溯构造方案.
时间复杂度 \(\mathcal{O}(26L\cdot 2^n)\),\(L\) 是 \(n\) 个字符串的长度之和.
代码
//author:kzssCCC
#include <bits/stdc++.h>
using namespace std;
using ll = long long;
const int INF = 1e9;
void solve(){
int n;
cin >> n;
vector<string> s(n+1);
for (int i=1;i<=n;i++){
cin >> s[i];
}
vector<int> ref{0};
vector<vector<int>> next{vector<int>(26)};
for (int i=1;i<=n;i++){
int u = 0;
for (auto& ch:s[i]){
int c = ch-'A';
if (next[u][c]==0){
next.push_back(vector<int>(26));
ref.push_back(0);
next[u][c] = next.size()-1;
}
u = next[u][c];
}
ref[u] |= 1<<i-1;
}
int m = next.size();
vector<int> fail(m);
queue<int> q;
for (int c=0;c<26;c++){
if (next[0][c]){
q.push(next[0][c]);
}
}
while (!q.empty()){
int u = q.front();
q.pop();
for (int c=0;c<26;c++){
if (next[u][c]){
fail[next[u][c]] = next[fail[u]][c];
ref[next[u][c]] |= ref[fail[next[u][c]]];
q.push(next[u][c]);
}
else{
next[u][c] = next[fail[u]][c];
}
}
}
queue<pair<int,int>> qe;
qe.emplace(0,0);
vector<vector<int>> dis(m,vector<int>(1<<n,INF));
vector<vector<array<int,3>>> pre(m,vector<array<int,3>>(1<<n,{-1,-1,-1}));
dis[0][0] = 0;
int last = -1;
while (!qe.empty()){
auto [mask,u] = qe.front();
qe.pop();
for (int c=0;c<26;c++){
int v = next[u][c];
int nmask = mask | ref[v];
if (dis[u][mask]+1<dis[v][nmask]){
dis[v][nmask] = dis[u][mask]+1;
pre[v][nmask] = {c,mask,u};
qe.emplace(nmask,v);
if (nmask==(1<<n)-1){
last = v;
break;
}
}
}
if (last!=-1) break;
}
// cout << last << '\n';
string res;
int cur = last;
int mask = (1<<n)-1;
while (cur!=0){
res += (char)(pre[cur][mask][0]+'A');
int nmask = pre[cur][mask][1];
int v = pre[cur][mask][2];
mask = nmask;
cur = v;
}
reverse(res.begin(),res.end());
cout << res << '\n';
}
int main(){
ios::sync_with_stdio(false);
cin.tie(0);
int t = 1;
// cin >> t;
while (t--) solve();
return 0;
}

浙公网安备 33010602011771号