Bzoj1195——最短母串(AC自动机)

1195: [HNOI2006]最短母串

Time Limit: 10 Sec   Memory Limit: 32 MB
Submit: 2037   Solved: 689

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<cstdio>
#include<iostream>
#include<cmath>
#include<cstring>
#include<algorithm>
#include<cstdlib>
#include<queue>
using namespace std;
const int N=605;
int L1[N*(1<<12)],L2[N*(1<<12)],n,ans[N],num=0,ch[N][26],p[N],end[N],S,tot,q[670],head,tail;
queue<int>q1,q2;
bool vis[N][(1<<12)];
char s[60];
void init() {S=tot=1;memset(end,0,sizeof end);return;}
void insert(char *s,int id){
    int len=strlen(s),now=S;
    for(int i=0;i<len;i++){
        if(!ch[now][s[i]-'A']) ch[now][s[i]-'A']=++tot;
        now=ch[now][s[i]-'A'];
    }
    end[now]|=(1<<id);
}
void pre(){
    head=1; tail=0;
    for(int i=0; i<26; i++)
        if(ch[S][i]){q[++tail]=ch[S][i];p[ch[S][i]]=S;} else ch[S][i]=S;
    while(head<=tail){
        int u=q[head++];
        int v,r;
        for(int i=0; i<26; i++){
            if(ch[u][i]){
                p[ch[u][i]]=ch[p[u]][i];
                end[ch[u][i]]|=end[ch[p[u]][i]];
                q[++tail]=ch[u][i];
            }
            else ch[u][i]=ch[p[u]][i];
        }
    }
    return;
}
void solve(){
    head=1; tail=1;int ed=(1<<n)-1;
    q1.push(S),q2.push(0);
    while(head<=tail){
        int u=q1.front();q1.pop();
        int e=q2.front();q2.pop();
        if(e==ed){
            for(;head>1; head=L2[head]){ans[++num]=L1[head];}
            for(int i=num; i; i--) printf("%c",ans[i]+'A');
            return;
        }
        for(int i=0; i<26; i++){
            if(!vis[ch[u][i]][e|end[ch[u][i]]]){
                L1[++tail]=i;
                L2[tail]=head;
                q1.push(ch[u][i]);
                q2.push(e|end[ch[u][i]]);
                vis[ch[u][i]][e|end[ch[u][i]]]=1;
            }
        }
        head++;
    }
}
int main(){
    scanf("%d",&n);
    init();
    for(int i=0; i<n; i++)scanf("%s",s),insert(s,i);
    pre();
    solve();
    return 0;
}

miao~~~

猜你喜欢

转载自blog.csdn.net/wangyh1008/article/details/81507638
今日推荐