最短母串

1483:最短母串

时间限制: 1000 ms         内存限制: 65536 KB

【题目描述】

原题来自:HNOI 2006

给定 n个字符串 S1,S2,?,Sn?? ,要求找到一个最短的字符串 T,使得这 n 个字符串都是 T的子串。

【输入】

第一行是一个正整数 n,表示给定的字符串的个数;

以下的 n行,每行有一个全由大写字母组成的字符串。

【输出】

只有一行,为找到的最短的字符串 T。

在保证最短的前提下,如果有多个字符串都满足要求,那么必须输出按字典序排列的第一个。

【输入样例】

2
ABCD
BCDABC

【输出样例】

ABCDABC

【提示】

数据范围:

对于全部数据,1≤n≤12,1≤∣Si∣≤50。

【题解】

看到n感觉可以状压。

首先建出AC自动机,在AC自动机上按字典序bfs,用book[i][s] 表示在i点,已经过了s的状态,这个点已经走过了。

复杂度O(1<<n * (n*600)).

代码如下:

#include<bits/stdc++.h>
using namespace std;
const int N=605;
int n,cnt,ji[N],ans;
char c[55];
struct trie
{
    int er[26],fail,pan;
}a[N];
inline void insert(int jia)
{
    int len=strlen(c+1),now=0;
    for(int i=1;i<=len;i++)
    {
        if(!a[now].er[c[i]-'A']) a[now].er[c[i]-'A']=++cnt;
        now=a[now].er[c[i]-'A'];
    }
    a[now].pan|=(1<<jia);
}
queue <int> que;
inline void get_fail()
{
    for(int i=0;i<=25;i++)
        if(a[0].er[i])
            que.push(a[0].er[i]);
    while(!que.empty())
    {
        int now=que.front();que.pop();
        a[now].pan|=a[a[now].fail].pan;
        for(int i=0;i<=25;i++)
        {
            if(a[now].er[i])
            {
                a[a[now].er[i]].fail=a[a[now].fail].er[i];
                que.push(a[now].er[i]);
            }
            else 
                a[now].er[i]=a[a[now].fail].er[i];
        }
    }
}
bool book[605][4097];
struct bfs
{
    int fa,shi,zai,s;
}b[2457605];
inline void solve()
{
    int head=1,tail=1;
    book[0][0]=1;
    while(head<=tail)
    {
        int now=b[head].zai,nz=b[head].s;
        if(nz==(1<<n)-1)
        {
            int hu=head;
            while(hu!=1)
            {
                ji[++ans]=b[hu].shi;
                hu=b[hu].fa;
            }
            return;
        }
        for(int i=0;i<=25;i++)
        {
            int v=a[now].er[i];
            int zt=nz|a[v].pan;
            if(book[v][zt]) continue;
            book[v][zt]=1;
            b[++tail]={head,i,v,zt};
        }
        head++;
    }
}
int main()
{
    scanf("%d",&n);
    for(int i=1;i<=n;i++)
    {
        scanf("%s",c+1);
        insert(i-1);
    }
    get_fail();
    solve();
    reverse(ji+1,ji+ans+1);
    for(int i=1;i<=ans;i++)
        cout<<(char)(ji[i]+'A');
}
View Code
原文地址:https://www.cnblogs.com/betablewaloot/p/12158618.html