zoukankan      html  css  js  c++  java
  • BZOJ1195:[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

    Solution

    先建好$AC$自动机,然后每个结束点用状压标记一下包含状态。

    从根开始$BFS$,找到答案就停止,这样可以保证最短。

    每次扩展按字典序从小到大扩展,这样可以保证字典序最小。

    $BFS$的时候存下前驱输出答案就好了。

    建立$fail$指针的时候,当$now$点建完的时候,要往上暴跳$fail$,把$fail$上包含状态并到$now$上!我沙茶忘了这里找了好久错误TAT

    卡空间真的丧病……

    Code

     1 #include<iostream>
     2 #include<cstring>
     3 #include<cstdio>
     4 #include<queue>
     5 #define N (601)
     6 using namespace std;
     7 
     8 struct Node{int p,S,id;};
     9 int n,sz,cnt,Son[N][26],End[N],Fail[N];
    10 int pre[N*3000],ans[N*3000];
    11 bool vis[N][1<<12];
    12 queue<int>q;
    13 queue<Node>Q;
    14 char s[N];
    15 
    16 void Insert(char s[],int id)
    17 {
    18     int now=0;
    19     for (int i=0,l=strlen(s); i<l; ++i)
    20     {
    21         int x=s[i]-'A';
    22         if (!Son[now][x]) Son[now][x]=++sz;
    23         now=Son[now][x];
    24     }
    25     End[now]|=(1<<(id-1));
    26 }
    27 
    28 void Build_Fail()
    29 {
    30     for (int i=0; i<26; ++i)
    31         if (Son[0][i]) q.push(Son[0][i]);
    32     while (!q.empty())
    33     {
    34         int now=q.front(); q.pop();
    35         for (int i=0; i<26; ++i)
    36         {
    37             if (!Son[now][i])
    38             {
    39                 Son[now][i]=Son[Fail[now]][i];
    40                 continue;
    41             }
    42             Fail[Son[now][i]]=Son[Fail[now]][i];
    43             q.push(Son[now][i]);
    44         }
    45         int t=Fail[now];
    46         while (t && !End[t]) t=Fail[t];
    47         End[now]|=End[t];
    48     }
    49 }
    50 
    51 void Print(int x)
    52 {
    53     if (!x) return;
    54     Print(pre[x]); printf("%c",ans[x]+'A');
    55 }
    56 
    57 void Solve()
    58 {
    59     Q.push((Node){0,0,0});
    60     vis[0][0]=true;
    61     while (!Q.empty())
    62     {
    63         Node tmp=Q.front(); Q.pop();
    64         int p=tmp.p,S=tmp.S;
    65         if (S==(1<<n)-1) {Print(tmp.id); return;}
    66         for (int i=0; i<26; ++i)
    67             if (!vis[Son[p][i]][S|End[Son[p][i]]])
    68             {
    69                 vis[Son[p][i]][S|End[Son[p][i]]]=true;
    70                 ++cnt; ans[cnt]=i; pre[cnt]=tmp.id;
    71                 Q.push((Node){Son[p][i],S|End[Son[p][i]],cnt});
    72             }
    73     }
    74 }
    75 
    76 int main()
    77 {
    78     scanf("%d",&n);
    79     for (int i=1; i<=n; ++i)
    80         scanf("%s",s),Insert(s,i);
    81     Build_Fail(); Solve();
    82 }
  • 相关阅读:
    LeetCode 79. 单词搜索
    LeetCode 1143. 最长公共子序列
    LeetCode 55. 跳跃游戏
    LeetCode 48. 旋转图像
    LeetCode 93. 复原 IP 地址
    LeetCode 456. 132模式
    LeetCode 341. 扁平化嵌套列表迭代器
    LeetCode 73. 矩阵置零
    LeetCode 47. 全排列 II
    LeetCode 46. 全排列
  • 原文地址:https://www.cnblogs.com/refun/p/10028975.html
Copyright © 2011-2022 走看看