hdu 3247 Resource Archiver (ac自动机+BFS+状压dp)

来源:互联网 发布:h3c路由器端口映射 sql 编辑:程序博客网 时间:2024/06/06 01:05

题意:

给出n个资源串,m个病毒串,现在要如何连接资源串使得不含病毒串(可以重叠)。

题解:

真心不会做。

这题注意点好多,稍不留意就wa。

看了题解我是这样理解的,我么可以把资源串和病毒串都放到ac机上,这样的做是为了把病毒串挑掉。在建ac机时,通过判断fail指针对应节点是否是病毒串,然后将fail指针的内容根性到这个节点。同理对于资源串也用相同方法。我们这样设置标记,病毒串ID=-1,资源串ID=对应状态(比如编号是i那么ID=1<<i)。后面建ac机可以整合这些状态。接着还要BFS得到剔除病毒串后可以用资源串到各个资源串的距离,这个方法很巧秒。之后就可以状压了dp[s][i]状态为s,ac机上节点i对应的最小长度。i不一定要在s中,因为可以通过多个部分整合成一个部分。其实建ac机时就将包含关系的资源串整合成了一个串,操作很巧妙的。


#include<iostream>#include<math.h>#include<stdio.h>#include<algorithm>#include<string.h>#include<vector>#include<queue>#include<map>#include<set>using namespace std;#define B(x) (1<<(x))typedef long long ll;const int oo=0x3f3f3f3f;const ll OO=1LL<<61;const ll MOD=20090717;const int maxn=1005;const int SIZE=60005;const int alph=2;char str[maxn];int dp[B(10)+5][11];int pos[11];int dis[SIZE];int maze[11][11];struct AC{    int next[SIZE][alph],fail[SIZE],ID[SIZE];    int root,cnt;    void Init()    {        cnt=0;        root=newNode();    }    int newNode()    {        for(int i=0;i<alph;i++)            next[cnt][i]=-1;        ID[cnt++]=0;        return cnt-1;    }    void Insert(char buff[],int id)    {        int now=root;        int len=strlen(buff);        for(int i=0,k;i<len;i++)        {            k=buff[i]-'0';            if(next[now][k]==-1)                next[now][k]=newNode();            now=next[now][k];        }        ID[now]=id;    }    void build()    {        queue<int>Q;        fail[root]=root;        int now=root;        for(int i=0;i<alph;i++)        {            if(next[now][i]==-1)                next[now][i]=root;            else            {                fail[next[now][i]]=root;                Q.push(next[now][i]);            }        }        while(!Q.empty())        {            now=Q.front();            Q.pop();            if(ID[fail[now]]==-1) ID[now]=-1;///和病毒串一样因此要改成-1,这样就相当于删除了病毒串            else ID[now]|=ID[fail[now]];            for(int i=0;i<alph;i++)            {                if(next[now][i]==-1)                    next[now][i]=next[fail[now]][i];                else                {                    fail[next[now][i]]=next[fail[now]][i];                    Q.push(next[now][i]);                }            }        }    }    void cmin(int& a,int b)    {        if(a==-1) a=b;        else if(b<a) a=b;    }    void bfs(int s,int n)    {        queue<int>Q;        memset(dis,-1,sizeof dis);        dis[pos[s]]=0;        Q.push(pos[s]);        while(!Q.empty())        {            int u=Q.front();            Q.pop();            for(int i=0;i<2;i++)            {                int v=next[u][i];                if(dis[v]==-1&&ID[v]!=-1)///因此只要处理到邻接的点即可,并不是多个点的路径                {                    dis[v]=dis[u]+1;                    Q.push(v);                }            }        }        for(int i=0;i<n;i++)            maze[s][i]=dis[pos[i]];    }    int DP(int n)    {        int nCnt;        memset(maze,-1,sizeof maze);        pos[0]=0;        nCnt=1;        for(int i=0;i<cnt;i++) if(ID[i]>0) pos[nCnt++]=i;        for(int i=0;i<nCnt;i++)            bfs(i,nCnt);        memset(dp,0x3f,sizeof dp);        dp[0][0]=0;        int full=B(n)-1;        for(int s=0;s<=full;s++)        {            for(int i=0;i<nCnt;i++)            if(dp[s][i]!=oo)            {                //if(!(s&B(i)))continue;                for(int j=0;j<nCnt;j++)                if(maze[i][j]!=-1&&i!=j)                {                    int st=s|ID[pos[j]];                    cmin(dp[st][j],dp[s][i]+maze[i][j]);                }            }        }        int ans=oo;        for(int i=0;i<nCnt;i++)            cmin(ans,dp[full][i]);        return ans;    }};AC ac;int main(){    int n,m;    while(scanf("%d %d",&n,&m)!=EOF)    {        if(n==0&&m==0)break;        ac.Init();        for(int i=0;i<n;i++)        {            scanf("%s",str);            ac.Insert(str,B(i));        }        for(int i=0;i<m;i++)        {            scanf("%s",str);            ac.Insert(str,-1);        }        ac.build();        cout<<ac.DP(n)<<endl;    }    return 0;}/**5 201000111000001110001111000001110001100110001110001100111101110001100111101100010100111101100010011111000111000001110001111000110011110110001ans=66*/



0 0
原创粉丝点击