【HNOI2006】最短母串
【HNOI2006】最短母串
by AmanoKumiko
Description
给定\(n\)个字符串\(S1,S2,S3...Sn\),要求找到一个最短的字符串\(T\)使得这\(n\)个字符串都是\(T\)的子串。
Input
第一行是一个正整数\(n\),表示给定的字符串的个数;
以下的\(n\)行,每行有一个全由大写字母组成的字符串。
Output
只有一行,为找到的最短的字符串\(T\)。
在保证最短的前提下,如果有多个字符串都满足要求,那么必须输出按字典序排列的第一个。
Sample Input
2
ABCD
BCDABC
Sample Output
ABCDABC
Data Constraint
\(1<=n<=12\),\(1<=|Si|<=50\)
Solution
又一道AC自动机上dp套路题
1.建自动机
2.求出每个点匹配串的集合
3.设\(f[i][S]\)表示到第\(i\)个点,匹配串集合为\(S\)的最短长度
最妙的地方来了:
在AC自动机上每走一步相当于长度\(+1\),那么如果使用\(bfs\),第一个\(S=2^n-1\)的\(f\)就是答案,同理,第一次遍历到某个点,当前的\(f\)一定最优
故记录每个点从哪里转移过来,答案显然
Code
#include<bits/stdc++.h>
using namespace std;
#define F(i,a,b) for(int i=a;i<=b;i++)
#define Fd(i,a,b) for(int i=a;i>=b;i--)
#define Fs(i,a) for(int i=last[a];i;i=e[i].next)
#define P 610
#define N 20
#define L 60
int n,cnt,len[N],last[P],f[P][1<<12],inf,ct;
struct node{int en,next;}e[P*2];
struct mode{int pos,sta;};
void add(int a,int b){e[++cnt]=(node){b,last[a]};last[a]=cnt;}
char s[N][L],ch[P];
queue<int>q;
queue<mode>qq;
struct ACM{
mode pre[P][1<<12];
char pc[P][1<<12];
int son[P][26],fail[P],tmp[P],p;
void insert(int x){
int u=1;
F(j,1,len[x])!son[u][s[x][j]-'A']?u=son[u][s[x][j]-'A']=++p:u=son[u][s[x][j]-'A'];
tmp[u]|=1<<x-1;
}
void build(){
F(i,0,25)son[0][i]=1;q.push(1);
while(!q.empty()){
int u=q.front();q.pop();add(fail[u],u);
F(i,0,25){
int v=son[u][i],Fail=fail[u];
if(!v){son[u][i]=son[Fail][i];continue;}
add(u,v);fail[v]=son[Fail][i];q.push(v);
}
}
F(i,1,p) Fs(j,i)tmp[e[j].en]|=tmp[i];//匹配串的集合
}
void bfs(){
memset(f,127,sizeof(f));
inf=f[1][0];f[1][0]=0;
qq.push((mode){1,0});
while(!qq.empty()){
mode u=qq.front();qq.pop();
if(u.sta==(1<<n)-1){//得到最优解
while(pre[u.pos][u.sta].pos)ch[++ct]=pc[u.pos][u.sta],u=pre[u.pos][u.sta];
Fd(i,ct,1)printf("%c",ch[i]);
return;
}
F(i,0,25){
int v=son[u.pos][i];
if(f[v][u.sta|tmp[v]]==inf){
f[v][u.sta|tmp[v]]=f[u.pos][u.sta]+1;
pc[v][u.sta|tmp[v]]=i+'A';//转移字符
pre[v][u.sta|tmp[v]]=u;//转移位置及状态
qq.push((mode){v,u.sta|tmp[v]});
}
}//dp转移
}
}
}t;
int main(){
t.p=1;
scanf("%d",&n);
F(i,1,n)scanf("%s",s[i]+1),len[i]=strlen(s[i]+1),t.insert(i);
t.build();t.bfs();
return 0;
}