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 }
posted @ 2018-11-27 20:57  Refun  阅读(286)  评论(0编辑  收藏  举报