zoukankan      html  css  js  c++  java
  • BZOJ_1195_[HNOI2006]最短母串_AC自动机+BFS+分层图

    BZOJ_1195_[HNOI2006]最短母串_AC自动机+BFS+分层图

    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自动机

    然后因为n很小,每个节点维护fail到根的路径出现了哪些字符串(出现字符串的状态)

    分1<<n个层,f[i][j]表示到第i个节点,当前已经有了的字符串状态为j,最短需要几个字符。

    因为边权为1可以直接BFS一遍。

    记录一下从哪来的方便输出路径。

    代码:

    #include <cstdio>
    #include <cstring>
    #include <algorithm>
    using namespace std;
    #define N 650
    int ch[N][26],fail[N],Q[N*4250],l,r,n,sta[N],cnt=1,flg[N],path[N][1<<12],zifu[N][1<<12];
    char w[N];
    void insert(int x) {
        int p=1,i;
        for(i=1;w[i];i++) {
            int &k=ch[p][w[i]-'A'];
            if(!k) k=++cnt;
            p=k;
        }
        sta[p]|=(1<<(x-1));
    }
    void build_ac() {
        int i,p;
        for(i=0;i<26;i++) ch[0][i]=1;
        Q[r++]=1;
        while(l<r) {
            p=Q[l++];
            for(i=0;i<26;i++) {
                if(ch[p][i]) fail[ch[p][i]]=ch[fail[p]][i],Q[r++]=ch[p][i];
                else ch[p][i]=ch[fail[p]][i];
            }
            sta[p]|=sta[fail[p]];
        }
    }
    void print(int x,int y) {
        if(path[x][y]) {
            int d=path[x][y];
            print(Q[d],Q[d+1]);
        }
        printf("%c",zifu[x][y]+'A');
    }
    int main() {
        scanf("%d",&n);
        int mask=(1<<n)-1;
        int i;
        for(i=1;i<=n;i++) {
            scanf("%s",w+1); insert(i);
        }
        build_ac();
        l=r=0;
    	memset(path,-1,sizeof(path));
        Q[r++]=1; Q[r++]=0; path[1][0]=0;
        while(l<r) {
            // puts("FUCK");
            int x=Q[l++],y=Q[l++];
            for(i=0;i<26;i++) {
                int c=ch[x][i];
                if(path[c][y|sta[c]]==-1) {
                    path[c][y|sta[c]]=l-2;
                    zifu[c][y|sta[c]]=i;
                    if((y|sta[c])==mask) {
                        print(c,y|sta[c]); return 0;
                    }
                    Q[r++]=c; Q[r++]=y|sta[c];
                }
            }
        }
    }
    

      

  • 相关阅读:
    firefox、chrome的DNS缓存清除方法
    MySQL中查询所有数据库占用磁盘空间大小和单个库中所有表的大小的sql语句
    PHP获取当前页面的网址
    JAVA接单10大平台
    线程
    创建一个简单的迭代器
    2016-09-20
    C# 静态构造函数
    ASP.NET MVC 右键点击添加没有区域(Area)、控制器、试图等选项
    Git的使用--如何将本地项目上传到Github(两种简单、方便的方法)
  • 原文地址:https://www.cnblogs.com/suika/p/9186948.html
Copyright © 2011-2022 走看看