BZOJ 1195 [HNOI2006]最短母串 (Trie图+状压+bfs最短路)

BZOJ1195 LOJ10061

题目大意:给你$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 }

 

posted @ 2018-11-24 19:44  guapisolo  阅读(273)  评论(0编辑  收藏  举报