HDU3247-(AC自动机+spfa+状压dp)

来源:互联网 发布:中国向何处去 知乎 编辑:程序博客网 时间:2024/06/06 00:23

题意:给你n个资源串和m个病毒串然后让你求最少需要多少个01字符才能做出不含病毒串并且含有所有的资源串的字符串

题解:先跑一边AC自动机然后求出所有结点是资源串的结尾但是不是病毒串的结尾的结点,最后求这些结点到其他结点的最短距离,注意的是初始是空串所有0那个结点也要算进去,因为结点对应的数值很大但是满足条件的很少所以我们要给满足条件的结点重新编号,最后就是二维dp(第一维表示含有哪几个资源串,第二维表示毅哪个结点结尾)而其对应的数值就是到达该状态的时候的最小长度

#include<iostream>#include<cstring>#include<queue>#include<cstdio>#include<cstring>using namespace std;#define mes(a,b) memset(a,b,sizeof(a))const int maxnode = 1e5+5;const int inf = 0x3f3f3f3f;int n,m;struct tried{    int ch[maxnode][2];    int v[maxnode];    int vis[maxnode];    int f[maxnode];    int dis[maxnode];    int dp[1234][205];    int path[205][205];    int pos[205];    int sz,cnt;    void init(){        sz = 1;        mes(ch[0],0);    }    void insert(char *s,bool flag,int id){        int len = strlen(s);        int u = 0;        for(int i = 0; i < len; i++){            int d = s[i]-'0';            if(!ch[u][d]){                mes(ch[sz],0);                v[sz] = 0;                vis[sz] = 0;                f[sz] = 0;                ch[u][d] = sz++;            }            u = ch[u][d];        }        flag?vis[u] = 1:v[u]|=(1<<id);    }    void getfail(){        int u = 0;        queue<int>q;        for(int i = 0; i < 2; i++)            if(ch[u][i])                q.push(ch[u][i]);        while(!q.empty()){            u = q.front();            q.pop();            vis[u] |= vis[f[u]];            v[u] |= v[f[u]];            for(int i = 0; i < 2; i++){                if(!ch[u][i]){                    ch[u][i] = ch[f[u]][i];                    continue;                }                int ret = ch[u][i];                f[ret] = ch[f[u]][i];                q.push(ret);            }        }    }    void spfa(int s){        queue<int>q;        q.push(pos[s]);        mes(dis,inf);        dis[pos[s]] = 0;        while(!q.empty()){            int u = q.front();            q.pop();            for(int i = 0; i < 2; i++){                int ret = ch[u][i];                if(!vis[ret]){                    if(dis[ret]==inf){                        dis[ret] = dis[u]+1;                        q.push(ret);                    }                }            }        }        for(int i = 0; i < cnt; i++)            path[s][i] = dis[pos[i]];    }    int solve(){        cnt = 0;        pos[cnt++] = 0;        for(int i = 0; i < sz; i++)            if(v[i]&&!vis[i])                pos[cnt++] = i;        for(int i = 0; i < cnt; i++)            spfa(i);        mes(dp,inf);        dp[0][0] = 0;        int d = (1<<n);        for(int i = 0; i < d; i++)            for(int j = 0; j < cnt; j++){                if(dp[i][j]==inf)                    continue;                for(int k = 0; k < cnt; k++){                    int nex = v[pos[k]]|i;                    dp[nex][k] = min(dp[nex][k],dp[i][j]+path[j][k]);                }            }        int ans = inf;        for(int j = 0; j < cnt; j++)            ans = min(ans,dp[d-1][j]);        return ans;    }}word;char s[1005];int main(){    while(scanf("%d%d",&n,&m),n||m){        word.init();        for(int i = 0; i < n; i++){            scanf("%s",s);            word.insert(s,0,i);        }        for(int i = 0; i < m; i++){            scanf("%s",s);            word.insert(s,1,i);        }        word.getfail();        printf("%d\n",word.solve());    }    return 0;}



原创粉丝点击