zoukankan      html  css  js  c++  java
  • BZOJ1195[HNOI2006]最短母串——AC自动机+BFS+状态压缩

    题目描述

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

    输入

    第一行是一个正整数n(n<=12),表示给定的字符串的个数。
    以下的n行,每行有一个全由大写字母组成的字符串。每个字符串的长度不超过50.

    输出

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

    样例输入

    2
    ABCD
    BCDABC

    样例输出

    ABCDABC
     
    题意是找一个最短的母串包含所有给出的字符串,多模匹配显然是AC自动机,把给出的所有串建在AC自动机上,问题就可以转化成了在AC自动机上经过所有串的终止节点所走的最少步数是多少。因为给出的串很少,所以可以用二进制来表示已经经过了哪个串的终止节点。然后用bfs(保证母串最短)按字典序(保证答案是字典序排列第一个)跑最短路并记录中间路径直到走到某个点的状态是(1<<n)-1为止。可以把整个过程看成是分层图(一个状态是一层)最短路,每个点在每个状态下只能遍历一次,当到达(1<<n)-1那一层就代表找到了最短母串。
    最后附上代码。
    #include<cmath>
    #include<queue>
    #include<cstdio>
    #include<cstring>
    #include<iostream>
    #include<algorithm>
    using namespace std;
    int n;
    int cnt;
    int num;
    char s[100];
    int t1[2460000];
    int t2[2460000];
    int end[605];
    int ans[605];
    int fail[1000];
    int a[605][26];
    int vis[605][4100];
    void build(char *s,int x)
    {
        int now=0;
        int len=strlen(s);
        for(int i=0;i<len;i++)
        {
            if(!a[now][s[i]-'A'])
            {
                a[now][s[i]-'A']=++cnt;
            }
            now=a[now][s[i]-'A'];
        }
        end[now]|=(1<<x);
    }
    void getfail()
    {
        queue<int>q;
        for(int i=0;i<26;i++)
        {
            if(a[0][i])
            {
                fail[a[0][i]]=0;
                q.push(a[0][i]);
            }
        }
        while(!q.empty())
        {
            int now=q.front();
            q.pop();
            for(int i=0;i<26;i++)
            {
                if(a[now][i])
                {
                    fail[a[now][i]]=a[fail[now]][i];
                    end[a[now][i]]|=end[a[fail[now]][i]];
                    q.push(a[now][i]);
                }
                else
                {
                    a[now][i]=a[fail[now]][i];
                }
            }
        }
        return ;
    }
    void bfs()
    {
        queue<int>q1;
        queue<int>q2;
        q1.push(0);
        q2.push(0);
        int l=1;
        int r=1;
        while(l<=r)
        {
            int now=q1.front();
            int e=q2.front();
            q1.pop();
            q2.pop();
            if(e==((1<<n)-1))
            {
                for(;l>1;l=t2[l])
                {
                    ans[++num]=t1[l];
                }
                for(int i=num;i;i--)
                {
                    printf("%c",ans[i]+'A');
                }
                return;
            }
            for(int i=0;i<26;i++)
            {
                if(!vis[a[now][i]][e|end[a[now][i]]])
                {
                    t1[++r]=i;
                    t2[r]=l;
                    q1.push(a[now][i]);
                    q2.push(e|end[a[now][i]]);
                    vis[a[now][i]][e|end[a[now][i]]]=1;
                }
            }
            l++;
        }
    }
    int main()
    {
        scanf("%d",&n);
        for(int i=0;i<n;i++)
        {
            scanf("%s",s);
            build(s,i);
        }
        getfail();
        bfs();
        return 0;
    }
  • 相关阅读:
    设计模式之观察者模式
    设计模式之代理模式
    用Javascript模拟微信飞机大战游戏
    [Leetcode] Remove Duplicates from Sorted List II
    [Leetcode] Remove Duplicates from Sorted List
    [Leetcode] Remove Duplicates from Sorted Array II
    [Leetcode] Palindrome Number
    [Leetcode] Decode Ways
    [Leetcode] Climbing Stairs
    [Leetcode] Maximum Subarray
  • 原文地址:https://www.cnblogs.com/Khada-Jhin/p/9169021.html
Copyright © 2011-2022 走看看