BZOJ1195[HNOI2006]最短母串——AC自动机+BFS+状态压缩

题目描述

给定n个字符串(S1,S2,„,Sn),要求找到一个最短的字符串T,使得这n个字符串(S1,S2,„,Sn)都是T的子串。

输入

第一行是一个正整数n(n<=12),表示给定的字符串的个数。
以下的n行,每行有一个全由大写字母组成的字符串。每个字符串的长度不超过50.

输出

只有一行,为找到的最短的字符串T。在保证最短的前提下,
如果有多个字符串都满足要求,那么必须输出按字典序排列的第一个。

样例输入

2
ABCD
BCDABC

样例输出

ABCDABC
 
题意是找一个最短的母串包含所有给出的字符串,多模匹配显然是AC自动机,把给出的所有串建在AC自动机上,问题就可以转化成了在AC自动机上经过所有串的终止节点所走的最少步数是多少。因为给出的串很少,所以可以用二进制来表示已经经过了哪个串的终止节点。然后用bfs(保证母串最短)按字典序(保证答案是字典序排列第一个)跑最短路并记录中间路径直到走到某个点的状态是(1<<n)-1为止。可以把整个过程看成是分层图(一个状态是一层)最短路,每个点在每个状态下只能遍历一次,当到达(1<<n)-1那一层就代表找到了最短母串。
最后附上代码。
  1 #include<cmath>
  2 #include<queue>
  3 #include<cstdio>
  4 #include<cstring>
  5 #include<iostream>
  6 #include<algorithm>
  7 using namespace std;
  8 int n;
  9 int cnt;
 10 int num;
 11 char s[100];
 12 int t1[2460000];
 13 int t2[2460000];
 14 int end[605];
 15 int ans[605];
 16 int fail[1000];
 17 int a[605][26];
 18 int vis[605][4100];
 19 void build(char *s,int x)
 20 {
 21     int now=0;
 22     int len=strlen(s);
 23     for(int i=0;i<len;i++)
 24     {
 25         if(!a[now][s[i]-'A'])
 26         {
 27             a[now][s[i]-'A']=++cnt;
 28         }
 29         now=a[now][s[i]-'A'];
 30     }
 31     end[now]|=(1<<x);
 32 }
 33 void getfail()
 34 {
 35     queue<int>q;
 36     for(int i=0;i<26;i++)
 37     {
 38         if(a[0][i])
 39         {
 40             fail[a[0][i]]=0;
 41             q.push(a[0][i]);
 42         }
 43     }
 44     while(!q.empty())
 45     {
 46         int now=q.front();
 47         q.pop();
 48         for(int i=0;i<26;i++)
 49         {
 50             if(a[now][i])
 51             {
 52                 fail[a[now][i]]=a[fail[now]][i];
 53                 end[a[now][i]]|=end[a[fail[now]][i]];
 54                 q.push(a[now][i]);
 55             }
 56             else
 57             {
 58                 a[now][i]=a[fail[now]][i];
 59             }
 60         }
 61     }
 62     return ;
 63 }
 64 void bfs()
 65 {
 66     queue<int>q1;
 67     queue<int>q2;
 68     q1.push(0);
 69     q2.push(0);
 70     int l=1;
 71     int r=1;
 72     while(l<=r)
 73     {
 74         int now=q1.front();
 75         int e=q2.front();
 76         q1.pop();
 77         q2.pop();
 78         if(e==((1<<n)-1))
 79         {
 80             for(;l>1;l=t2[l])
 81             {
 82                 ans[++num]=t1[l];
 83             }
 84             for(int i=num;i;i--)
 85             {
 86                 printf("%c",ans[i]+'A');
 87             }
 88             return;
 89         }
 90         for(int i=0;i<26;i++)
 91         {
 92             if(!vis[a[now][i]][e|end[a[now][i]]])
 93             {
 94                 t1[++r]=i;
 95                 t2[r]=l;
 96                 q1.push(a[now][i]);
 97                 q2.push(e|end[a[now][i]]);
 98                 vis[a[now][i]][e|end[a[now][i]]]=1;
 99             }
100         }
101         l++;
102     }
103 }
104 int main()
105 {
106     scanf("%d",&n);
107     for(int i=0;i<n;i++)
108     {
109         scanf("%s",s);
110         build(s,i);
111     }
112     getfail();
113     bfs();
114     return 0;
115 }
View Code

猜你喜欢

转载自www.cnblogs.com/Khada-Jhin/p/9169021.html
今日推荐