HDU 3247 Resource Archiver(AC自动机+BFS+状态DP)

来源:互联网 发布:福州爆米花网络 编辑:程序博客网 时间:2024/06/06 00:40

转载请注明出处,谢谢http://blog.csdn.net/acm_cxlove/article/details/7854526       by---cxlove

题目:给出n个资源,m个病毒,将资源串拼接成一个串,必须包含所有的资源串,可以重叠,但是不能包含病毒

问最小的长度为多少

http://acm.hdu.edu.cn/showproblem.php?pid=3247 

不会做,看题解啊看题解,看了也不会。。。。

将所有的资源串和病毒串都放在Trie树里建立起来,当然作上相应的标记。然后建立fail指针之后

从资源串的结尾出发,BFS,记录能到达其它资源串结尾的步数。得到所有资源串结尾状态的距离邻接阵。

之后是状态压缩DP

dp[i][j]表示资源串的状态为i时,当前处在Trie上的状态j,最短长度。

感觉静态的写得怪怪的,而且不直观。。

#include<iostream>#include<cstdio>#include<algorithm>#include<cstring>#include<cmath>#define eps 1e-10#define N 100005#define inf 1<<20#define zero(a) (fabs(a)<eps)#define lson (step<<1)#define rson (step<<1|1)using namespace std;struct Trie{    int next[2],fail;    int virus,source;    void Init(){next[0]=next[1]=0;fail=source=virus=0;}}tree[N];int n,m;int tot,cnt;int path[205][205];int pos[205];int dp[1<<10][205];//dp[i][j]表示状态为i时,以j结尾的最少步数char str[50005];void Insert(char *s,int len,int kind){    int p=0;    for(int i=0;i<len;i++){        if(tree[p].next[s[i]-'0']==0){            tree[++tot].Init();            tree[p].next[s[i]-'0']=tot;        }        p=tree[p].next[s[i]-'0'];    }    if(kind>=0) tree[p].source=1<<kind;    else tree[p].virus=1;}void Bulid_fail(){    int que[N];    int head=0,tail=0;    que[tail++]=0;    while(head<tail){        int p=que[head++];        for(int i=0;i<2;i++){            if(tree[p].next[i]==0) tree[p].next[i]=tree[tree[p].fail].next[i];            else{                int q=tree[p].next[i];                if(p)  tree[q].fail=tree[tree[p].fail].next[i];                tree[q].source|=tree[tree[q].fail].source;                tree[q].virus|=tree[tree[q].fail].virus;                que[tail++]=q;            }        }    }}void Bfs(int u){    int que[N];    int head=0,tail=0;    int dist[N];    memset(dist,-1,sizeof(dist));    que[tail++]=pos[u];    dist[pos[u]]=0;    while(head<tail){        int p=que[head++];        for(int i=0;i<2;i++){            int q=tree[p].next[i];            if(dist[q]<0&&!tree[q].virus){                dist[q]=dist[p]+1;                que[tail++]=q;            }        }    }    for(int i=0;i<cnt;i++)        path[u][i]=dist[pos[i]];}int DP(){    memset(dp,-1,sizeof(dp));    dp[0][0]=0;    for(int i=0;i<(1<<n);i++){        for(int j=0;j<cnt;j++){            if(dp[i][j]<0) continue;            for(int k=0;k<cnt;k++){                if(path[j][k]<0) continue;                if(dp[i|tree[pos[k]].source][k]==-1) dp[i|tree[pos[k]].source][k]=dp[i][j]+path[j][k];                else dp[i|tree[pos[k]].source][k]=min(dp[i|tree[pos[k]].source][k],dp[i][j]+path[j][k]);            }        }    }    int ans=inf;    for(int i=0;i<cnt;i++)        if(dp[(1<<n)-1][i]!=-1) ans=min(ans,dp[(1<<n)-1][i]);    return ans==inf?-1:ans;}int main(){   // freopen("1.in","r",stdin);    while(scanf("%d%d",&n,&m)!=EOF&&n+m){        tree[0].Init();cnt=1;tot=0;        for(int i=0;i<n;i++){            scanf("%s",str);            Insert(str,strlen(str),i);        }        for(int i=0;i<m;i++){            scanf("%s",str);            Insert(str,strlen(str),-1);        }        Bulid_fail();        for(int i=1;i<=tot;i++)            if(tree[i].source)                pos[cnt++]=i;        for(int i=0;i<cnt;i++)            Bfs(i);        printf("%d\n",DP());    }    return 0;}