zoukankan      html  css  js  c++  java
  • Bzoj1195 [HNOI2006]最短母串 [AC自动机]

    Time Limit: 10 Sec  Memory Limit: 32 MB
    Submit: 1304  Solved: 439

    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

    暴力+状压:http://www.cnblogs.com/SilverNebula/p/6445487.html

    AC自动机+BFS

    这其实是我看到这题时最先有的思路,然而看到数据范围明显是为了状压设的,就写状压了。之后发现确实有AC自动机的解法,那么果断学习一发。

    (其实也需要状压)先建好AC自动机,标记好每个结点对应的包含串状态,然后从根节点开始BFS(BFS保证串最短),在每个状态从A到Z依次尝试扩展状态(保证字典序最小)

    实际跑出来不比普通状压慢多少(大概是因为我的普通状压跑得太慢233)

     1 #include<iostream>
     2 #include<cstdio>
     3 #include<algorithm>
     4 #include<cstring>
     5 #include<queue>
     6 using namespace std;
     7 const int mxn=605;
     8 int L1[mxn*(1<<12)],L2[mxn*(1<<12)];
     9 queue<int>q1,q2;
    10 bool vis[mxn][(1<<12)];
    11 int n;
    12 int ans[mxn],num=0;
    13 struct ACa{
    14     int t[mxn][26];
    15     int fail[mxn];
    16     int end[mxn];
    17     int S,cnt;
    18     int q[670],hd,tl;
    19     void init(){S=cnt=1;memset(end,0,sizeof end);return;}
    20     void insert(char *s,int id){
    21         int len=strlen(s),now=S;
    22         for(int i=0;i<len;i++){
    23             if(!t[now][s[i]-'A'])t[now][s[i]-'A']=++cnt;
    24             now=t[now][s[i]-'A'];
    25         }
    26         end[now]|=(1<<id);
    27     }
    28     void Build(){
    29         hd=1;tl=0;
    30         for(int i=0;i<26;i++)
    31             if(t[S][i]){q[++tl]=t[S][i];fail[t[S][i]]=S;}
    32             else t[S][i]=S;
    33         while(hd<=tl){
    34             int u=q[hd++];
    35             int v,r;
    36             for(int i=0;i<26;i++){
    37                 if(t[u][i]){
    38                     fail[t[u][i]]=t[fail[u]][i];
    39                     end[t[u][i]]|=end[t[fail[u]][i]];
    40                     q[++tl]=t[u][i];
    41                 }
    42                 else t[u][i]=t[fail[u]][i];
    43             }
    44         }
    45         return;
    46     }
    47     void solve(){
    48         hd=1;tl=1;int ed=(1<<n)-1;
    49         q1.push(S),q2.push(0);
    50         while(hd<=tl){
    51             int u=q1.front();q1.pop();
    52             int e=q2.front();q2.pop();
    53 //            printf("  e:%d
    ",e);
    54             if(e==ed){//结束状态 
    55                 for(;hd>1;hd=L2[hd]){ans[++num]=L1[hd];}
    56                 for(int i=num;i;i--)printf("%c",ans[i]+'A');
    57                 return;
    58             }
    59             for(int i=0;i<26;i++){
    60                 if(!vis[t[u][i]][e|end[t[u][i]]]){
    61                     L1[++tl]=i;
    62                     L2[tl]=hd;
    63                     q1.push(t[u][i]);
    64                     q2.push(e|end[t[u][i]]);
    65                     vis[t[u][i]][e|end[t[u][i]]]=1;
    66                 }
    67             }
    68             hd++;
    69         }
    70     }
    71 }ac;
    72 char s[60];
    73 int main(){
    74     int i,j;
    75     scanf("%d",&n);
    76     ac.init();
    77     for(i=0;i<n;i++)scanf("%s",s),ac.insert(s,i);
    78 //    for(i=1;i<=ac.cnt;i++)if(ac.end[i])printf("%d %d
    ",i,ac.end[i]);
    79     ac.Build();
    80     ac.solve();
    81     return 0;
    82 }
  • 相关阅读:
    利用 fsockopen() 函数开放端口扫描器
    oracle如何返回列名作为第一条数据简单解决
    redis
    MYSQL
    JUC 多线程
    java单例模式六种实现方式
    java.net.URISyntaxException 问题解决
    Calender类——字段值介绍
    Dorado开发——树形下拉框
    Java—— 一点关于String的转换
  • 原文地址:https://www.cnblogs.com/SilverNebula/p/6445516.html
Copyright © 2011-2022 走看看