• 最短母串


    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
  • 相关阅读:
    统计0到n之间1的个数
    CUMCM--总结
    赫尔曼算法及应用
    css3实现连续不断的波浪
    svg优雅降级技术
    正则的一点经验
    vue 配合 element-ui使用搭建环境时候遇到的坑
    gulpfile.js备份
    最新版浏览器报错net::ERR_INSECURE_RESPONSE原因
    移动web端使用rem实现自适应原理
  • 原文地址:https://www.cnblogs.com/betablewaloot/p/12158618.html
Copyright © 2020-2023  润新知