题目描述
给定n个字符串(S1,S2,„,Sn),要求找到一个最短的字符串T,使得这n个字符串(S1,S2,„,Sn)都是T的子串。
输入
第一行是一个正整数n(n<=12),表示给定的字符串的个数。
以下的n行,每行有一个全由大写字母组成的字符串。每个字符串的长度不超过50.
输出
只有一行,为找到的最短的字符串T。在保证最短的前提下,
如果有多个字符串都满足要求,那么必须输出按字典序排列的第一个。
样例输入
2
ABCD
BCDABC
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 }