Description
给定n个字符串(S1,S2,„,Sn),要求找到一个最短的字符串T,使得这n个字符串(S1,S2,„,Sn)都是T的子串。
Input
第一行是一个正整数n(n<=12),表示给定的字符串的个数。
以下的n行,每行有一个全由大写字母组成的字符串。每个字符串的长度不超过50.
Output
只有一行,为找到的最短的字符串T。在保证最短的前提下,
如果有多个字符串都满足要求,那么必须输出按字典序排列的第一个。
Sample Input
2
ABCD
BCDABC
Sample Output
ABCDABC
还是在AC自动机上建出所有读入的串,并且我们可以用一个二进制数来记录每个串是否被选取的状态。由于要求的是最短的,所以我们进行BFS,第一个完成二进制所有位上都是以的状态就是题目要求的状态,又由于要字典序最小,所以BFS时从A到Z枚举即可。
#include<bits/stdc++.h>
#define MAXN 605
using namespace std;
int read(){
char c;int x;while(c=getchar(),c<'0'||c>'9');x=c-'0';
while(c=getchar(),c>='0'&&c<='9') x=x*10+c-'0';return x;
}
int n,cnt=1,nxt[MAXN][26],p[MAXN],fail[MAXN],q[MAXN],ans[MAXN],vis[MAXN][4100];
struct node{
int p,status;
};
struct stevensonson{
int lst,num;
}L[MAXN*4100];
queue<node> a;
char s[52];
void build(int x){
int l=strlen(s+1),pl=1;
for(int i=1;i<=l;i++){
int x=s[i]-'A';
if(nxt[pl][x]) pl=nxt[pl][x];
else{
++cnt;nxt[pl][x]=cnt;pl=cnt;
}
}
p[cnt]|=(1<<x-1);
}
void getfail(){
int h=0,t=0;
for(int i=0;i<26;i++)
if(nxt[1][i]) fail[q[++t]=nxt[1][i]]=1;
else nxt[1][i]=1;
while(h<t){
int now=q[++h];
for(int i=0;i<26;i++){
if(nxt[now][i]){
p[nxt[now][i]]|=p[nxt[fail[now]][i]];
fail[q[++t]=nxt[now][i]]=nxt[fail[now]][i];
if(!fail[nxt[now][i]]) fail[nxt[now][i]]=1;
}
else nxt[now][i]=nxt[fail[now]][i];
}
}
}
void bfs(){
int h=0,t=1,k=0,end=(1<<n)-1;a.push((node){1,0});
while(h<t){
node e=a.front();a.pop();h++;
if(e.status==end){
for(int i=h;i>1;i=L[i].lst) ans[++k]=L[i].num;
for(int i=k;i;i--) putchar('A'+ans[i]);
return;
}
for(int i=0;i<26;i++){
int to=nxt[e.p][i];
if(vis[to][e.status|p[to]]) continue;
vis[to][e.status|p[to]]=1;L[++t].lst=h;L[t].num=i;
a.push((node){to,e.status|p[to]});
}
}
}
int main()
{
n=read();
for(int i=1;i<=n;i++){
scanf("%s",s+1);
build(i);
}
getfail();
bfs();
return 0;
}