• 2782: [HNOI2006]最短母串


    2782: [HNOI2006]最短母串

    Time Limit: 1 Sec  Memory Limit: 128 MB
    Submit: 3  Solved: 2
    [Submit][Status][Web Board]

    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

    HINT

     

    Source

     题解:

      

      首先我的思路十分傻叉,是f[i][j][k]f[i][j][k]表示长度为ii,在自动机上的节点为jj,包含子串的状态为kk可不可能.但这样复杂度直接爆炸.

      但是我们可以令f[i][j]f[i][j]表示在自动机上的节点为ii,包含子串的状态为jj时的最短长度.

      这样我们就转化成了边权均为1的单源最短路,BFS就行了.

      若按照字母字典序从小到大的顺序进行BFS,得出的就是字典序最小的答案了.

      (有点卡内存)

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<queue>
    #include<algorithm>
    using namespace std;
    const int inf=1e9;
    struct Node{
        int fail,ch[26],val;
        void clear(){
            fail=val=0;
            memset(ch,0,sizeof(ch));
        }
    }tr[605];
    int sz;
    int bin[20],n;
    void insert(char *s,int val){
        int u=0,len=strlen(s);
        for(int i=0;i<len;i++){
            int c=s[i]-'A';
            if(!tr[u].ch[c]){
                tr[u].ch[c]=++sz;
                tr[sz].clear();
            }
            u=tr[u].ch[c];
        }
        tr[u].val|=bin[val];
    }
    void build(){
        queue<int>q;q.push(0);
        while(!q.empty()){
            int u=q.front();q.pop();
            for(int i=0;i<26;i++){
                if(tr[u].ch[i]){
                    int v=tr[u].ch[i];
                    if(u)tr[v].fail=tr[tr[u].fail].ch[i];
                    q.push(v);
                }else tr[u].ch[i]=tr[tr[u].fail].ch[i];
            }
        }
    }
    int fromu[605][4100],froms[605][4100];
    bool vis[605][4100];
    void print(int u,int s){
        if(!u)return;
        print(fromu[u][s],froms[u][s]);
        for(int i=0;i<26;i++){
            int v=tr[fromu[u][s]].ch[i],t=froms[u][s];
            for(int p=v;p;p=tr[p].fail)
            t|=tr[p].val;
            if(v==u&&t==s){
                putchar('A'+i);
                break;
            }
        }
    }
    void bfs(){
        queue<int>q1,q2;
        q1.push(0);q2.push(0);
        vis[0][0]=1;
        while(!q1.empty()){
            int u=q1.front(),s=q2.front();q1.pop();q2.pop();
            for(int i=0;i<26;i++){
                int v=tr[u].ch[i],t=s;
                for(int p=v;p;p=tr[p].fail)
                t|=tr[p].val;
                if(!vis[v][t]){
                    vis[v][t]=1;
                    q1.push(v);q2.push(t);
                    fromu[v][t]=u;
                    froms[v][t]=s;
                    if(t==bin[n+1]-1){
                        print(v,t);
                        return;
                    }
                }
            }
        }
    }
    char s[55];
    int main(){
        scanf("%d",&n);
        tr[sz=0].clear();
        bin[1]=1;
        for(int i=2;i<20;i++)bin[i]=bin[i-1]<<1; 
        for(int i=1;i<=n;i++){
            scanf("%s",s);
            insert(s,i);
        }
        build();
        bfs();
        return 0;
    }
    View Code
     
  • 相关阅读:
    DOM(九)使用DOM设置文本框
    DOM(八)使用DOM控制表单
    DOM(七)使用DOM控制表格
    Javascript制作伸缩的二级菜单
    Javascript屏蔽鼠标的右键的两种方法。
    DOM(六)事件类型
    DOM(五)事件对象
    DOM(四)事件流
    DOM(三)使用DOM + Css
    Javascript一个在页面内追加元素的小例子
  • 原文地址:https://www.cnblogs.com/HQHQ/p/5369078.html
Copyright © 2020-2023  润新知