【题目链接】
【题意】
给定 n 个字符串 S1~Sn,要求找到一个最短的字符串 T,使得这 n 个字符串都是 T 的子串。
【题解】
类似于搜索+二进制记录状态的题目
搜索时利用BFS来跑,每一个结点的位置都可以用状态数组存起来,
判断是否为 (1<<n)- 1 即可。
在输出答案时需要递归实现,所以要一个辅助数组fa来记录上一个结点的位置。
1 #include<queue> 2 #include<cstdio> 3 #include<cstring> 4 #include<algorithm> 5 using namespace std; 6 const int N = 6e3+5; 7 const int M = 2e6+50; 8 const int Str_N = 605; 9 int Trie[N][26],fail[N],End[N]; 10 int vis[N][Str_N]; 11 int Q[M],St[M]; 12 int Fa[M]; 13 char str[M]; 14 int Head,Tail; 15 int n,idx; 16 char Str[Str_N]; 17 void print(int x){ 18 if(x==1) return ; 19 print(Fa[x]); 20 putchar(str[x]+'A'); 21 } 22 void Insert( char s[] , int Id ){ 23 int p = 0 ; 24 for(int i=0;s[i];i++){ 25 int t = s[i]-'A'; 26 if( !Trie[p][t] ) 27 Trie[p][t] = ++idx; 28 p = Trie[p][t]; 29 } 30 End[p] |= (1<<Id); 31 } 32 void Build(){ 33 Head = 1 , Tail = 0; 34 35 for(int i=0;i<26;i++){ 36 if( Trie[0][i] ){ 37 Q[++Tail] = Trie[0][i]; 38 fail[Trie[0][i]] = 0; 39 } 40 } 41 42 while( Head <= Tail ){ 43 int u = Q[Head++]; 44 45 for(int i=0;i<26;i++){ 46 int To = Trie[u][i]; 47 if( To ){ 48 fail[To] = Trie[fail[u]][i]; 49 Q[++Tail] = To ; 50 End[To] |= End[fail[To]]; 51 }else{ 52 Trie[u][i] = Trie[fail[u]][i]; 53 } 54 } 55 } 56 } 57 void Solve(){ 58 memset(Q,0,sizeof Q ); 59 60 61 Head = 0 , Tail = 1; 62 Q[1] = St[1] = 0 ; 63 vis[0][0] = 1 ; 64 65 while( Head < Tail ){ 66 int u = Q[++Head],S = St[Head]; 67 for(int i=0;i<26;i++){ 68 int To = Trie[u][i]; 69 int Ts = S | End[To] ; 70 if( vis[Ts][To] ) continue; 71 72 Fa[++Tail] = Head ; Q[Tail] = To ;str[Tail] = i; 73 vis[Ts][To] = 1 ;St[Tail] = Ts ; 74 75 if( Ts == (1<<n)-1 ){ 76 print(Tail); 77 putchar(' '); 78 return ; 79 } 80 } 81 } 82 } 83 int main() 84 { 85 scanf("%d",&n); 86 for(int i=0;i<n;i++){ 87 scanf("%s",Str); 88 Insert(Str,i); 89 } 90 Build(); 91 Solve(); 92 return 0; 93 } 94 95 /* 96 * 97 4 98 HNOI 99 NOIP 100 NOI 101 IOI 102 103 HNOIPIOI 104 */