BZOJ 1195 [HNOI2006]最短母串 (Trie图+状压+bfs最短路)
题目大意:给你$n$个模式串,求一个最短且字典序最小的文本串并输出这个串,$n<=12,len<=50$
首先对所有模式串构造$Trie$图,$Trie$图的性质和$DP$的性质简直是完美契合..
模式串数量很少,考虑状压
定义$f[x][s]$表示现在所在$Trie$图内的位置为$x$,已经匹配到的串的状态为$s$,此时需要文本串的最短长度
转移十分显然,$f[fail_{x}][s|ed[fail_{x}])]=min(f[x][s])+1$
最后找出最小的$f[x][(1<<n)-1]$
然而...直接这样转移我们没办法统计答案啊
考虑把问题放到图上,利用$bfs$队列先进先出的性质,如果我们优先把字典序小的状态推进队列,再通过记录当前状态第一次被更新时的上一层状态$fa[..]$的方式记录路径,跑$bfs$最短路,当队列中出现$s==(1<<n)-1$时立即结束,此时我们求得的一定是长度最短且字典序最小的答案!
注意可能有相同的串
注意不要忘了建$fail$树,如果某个节点是某个串的结尾,也要把它是这个串的结尾的信息传递到它在$fail$树中的子树中去!我没传竟然还有70分
1 #include <queue> 2 #include <cstdio> 3 #include <cstring> 4 #include <algorithm> 5 #define NN 610 6 #define MM 4100 7 #define ll long long 8 #define uint unsigned int 9 #define ull unsigned long long 10 #define inf 0x3f3f3f3f 11 #define idx(x) (x-'A') 12 using namespace std; 13 14 int n,cte; 15 int head[NN]; 16 char str[NN]; 17 struct Edge{int to,nxt;}edge[NN*2]; 18 void ae(int u,int v){ 19 cte++;edge[cte].nxt=head[u]; 20 edge[cte].to=v,head[u]=cte; 21 } 22 struct node{ 23 int x,s; 24 node(int x,int s):x(x),s(s){} 25 node(){} 26 }fa[NN][MM]; 27 int dis[NN][MM]; 28 namespace AC{ 29 int ch[NN][26],fail[NN],ed[NN],val[NN],tot; 30 void Build_Trie(char *str,int len,int id) 31 { 32 int x=0; 33 for(int i=1;i<=len;i++){ 34 if(!ch[x][idx(str[i])]) 35 ch[x][idx(str[i])]=++tot,val[tot]=idx(str[i]); 36 x=ch[x][idx(str[i])]; 37 }ed[x]|=(1<<(id-1)); 38 } 39 void Build_Fail() 40 { 41 queue<int>q; 42 for(int i=0;i<26;i++) 43 if(ch[0][i]) q.push(ch[0][i]); 44 while(!q.empty()) 45 { 46 int x=q.front();q.pop(); 47 ae(fail[x],x); 48 for(int i=0;i<26;i++) 49 { 50 if(ch[x][i]){ 51 fail[ch[x][i]]=ch[fail[x]][i]; 52 q.push(ch[x][i]); 53 }else{ 54 ch[x][i]=ch[fail[x]][i]; 55 } 56 } 57 } 58 q.push(0); 59 while(!q.empty()) 60 { 61 int x=q.front();q.pop(); 62 for(int j=head[x];j;j=edge[j].nxt){ 63 int v=edge[j].to; 64 ed[v]|=ed[x]; 65 q.push(v); 66 } 67 } 68 } 69 node Bfs() 70 { 71 queue<node>q; 72 memset(dis,0x3f,sizeof(dis)); 73 q.push(node(0,0)); 74 dis[0][0]=0; 75 node k1,k2; 76 int x,v,s,t; 77 while(!q.empty()) 78 { 79 k1=q.front();q.pop(); 80 x=k1.x,s=k1.s; 81 if(s==(1<<n)-1) return k1; 82 for(int i=0;i<26;i++) 83 { 84 v=ch[x][i],t=s|ed[v]; 85 if(dis[v][t]>dis[x][s]+1){ 86 dis[v][t]=dis[x][s]+1; 87 fa[v][t]=k1; 88 q.push(node(v,t)); 89 } 90 } 91 } 92 /*for(int i=1;i<=tot;i++) 93 printf("%d:%d\n",i,dis[i][(1<<n)-1]);*/ 94 } 95 char Ans[NN]; 96 void solve() 97 { 98 for(int i=1;i<=n;i++){ 99 scanf("%s",str+1); 100 int len=strlen(str+1); 101 Build_Trie(str,len,i);} 102 Build_Fail(); 103 node ans=Bfs(); 104 node a=ans; 105 int num=0; 106 while(a.x||a.s){ 107 Ans[++num]=val[a.x]+'A'; 108 a=fa[a.x][a.s];} 109 for(int i=num;i>0;i--) 110 printf("%c",Ans[i]); 111 puts(""); 112 } 113 }; 114 115 int main() 116 { 117 //freopen("t2.in","r",stdin); 118 scanf("%d",&n); 119 AC::solve(); 120 return 0; 121 }