【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;
}
posted @ 2021-02-04 11:41  冰雾  阅读(86)  评论(0编辑  收藏  举报