bzoj1195 神奇的ac自动机+状态压缩dp

/*

难的不是ac自动机,是状态压缩dp 

之前做了一两题类似题目,感觉理解的还不够透彻

*/

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<queue>
using namespace std;
const int mxn=605;
int L1[mxn*(1<<12)],L2[mxn*(1<<12)];
queue<int>q1,q2;
bool vis[mxn][(1<<12)];
int n;
int ans[mxn],num=0;
struct ACa{
    int t[mxn][26];
    int fail[mxn];
    int end[mxn];
    int S,cnt;
    int q[670],hd,tl;
    void init(){S=cnt=1;memset(end,0,sizeof end);return;}
    void insert(char *s,int id){
        int len=strlen(s),now=S;
        for(int i=0;i<len;i++){
            if(!t[now][s[i]-'A'])t[now][s[i]-'A']=++cnt;
            now=t[now][s[i]-'A'];
        }
        end[now]|=(1<<id);
    }
    void Build(){
        hd=1;tl=0;
        for(int i=0;i<26;i++)
            if(t[S][i]){q[++tl]=t[S][i];fail[t[S][i]]=S;}
            else t[S][i]=S;
        while(hd<=tl){
            int u=q[hd++];
            int v,r;
            for(int i=0;i<26;i++){
                if(t[u][i]){
                    fail[t[u][i]]=t[fail[u]][i];
                    end[t[u][i]]|=end[t[fail[u]][i]];
                    q[++tl]=t[u][i];
                }
                else t[u][i]=t[fail[u]][i];
            }
        }
        return;
    }
    void solve(){
        hd=1;tl=1;int ed=(1<<n)-1;
        q1.push(S),q2.push(0);
        while(hd<=tl){
            int u=q1.front();q1.pop();
            int e=q2.front();q2.pop();
//            printf("  e:%d\n",e);
            if(e==ed){//结束状态 
                for(;hd>1;hd=L2[hd]){ans[++num]=L1[hd];}
                for(int i=num;i;i--)printf("%c",ans[i]+'A');
                return;
            }
            for(int i=0;i<26;i++){
                if(!vis[t[u][i]][e|end[t[u][i]]]){
                    L1[++tl]=i;
                    L2[tl]=hd;
                    q1.push(t[u][i]);
                    q2.push(e|end[t[u][i]]);
                    vis[t[u][i]][e|end[t[u][i]]]=1;
                }
            }
            hd++;
        }
    }
}ac;
char s[60];
int main(){
    int i,j;
    scanf("%d",&n);
    ac.init();
    for(i=0;i<n;i++)scanf("%s",s),ac.insert(s,i);
//    for(i=1;i<=ac.cnt;i++)if(ac.end[i])printf("%d %d\n",i,ac.end[i]);
    ac.Build();
    ac.solve();
    return 0;
}

 

posted on 2018-10-16 12:06  zsben  阅读(213)  评论(0编辑  收藏  举报

导航