HDOJ-3427 & ZOJ-3190 Resource Archiver AC自动机压缩状态DP..

来源:互联网 发布:usb网络打印服务器设置 编辑:程序博客网 时间:2024/05/16 16:12

       先用resources和virus构造出AC自动机..

       本题最暴力的状态是很好想到的...dp[a][b][c]...代表a长度时某串后缀能到AC自动机点b..能得到c些resources..其中c是一个用十进制表示的二进制数..代表题目里最多10个resources的存在情况...可见此种dp..状态最多可为10000*60000*1024...爆空间爆时间..各种爆..爆得体无完肤!!..

       根据sha崽的提示..本题AC自动机里虽然点很多..但实际在更新转移中存在意义的点只有包含了resources的后缀点..而这些点的个数只有不超过50个..so..将这些后缀点之间的最短路径算出来...我就是直接枚举每个点BFS的...然后直接对这些存在转移意义的后缀点DP..瞬间时间和空间爆降阿..

       正如HDOJ本题Dicuss里有人说的..本题数据还是很弱的..我找了好多网上发布的AC代码...没有一个代码能够跑出完全正确的结果..错得最多的是Discuss里的:      

                3 3

                0001

                0000 

               10000

                010

                101

                111

     好不容易找到这个数据能过的..结果又一大堆没考虑resources相同的..还有一些连手算的简单数据都出错..这道题数据的不严谨.众AC代码漏洞百出.真是奇葩.

我WA了十多次的原因是因为..白痴了..一个赋初值的地方没注意到要清0..结果..WA得想吐..


Program:

#include<iostream>#include<stdio.h>#include<string.h>#include<math.h>#include<queue>#define oo 2000000000#define ll long longusing namespace std; struct node{       int son[2],fail,d,n;       bool w;}point[60005];int n,m,_2jie[12],dis[55][55],dp[55][1026],useful[55];char s[50005];queue<int> myqueue;int used[60005];int main(){          int len,i,j,x,h,k,num,ans,goal;       _2jie[0]=1;       for (i=1;i<=10;i++) _2jie[i]=_2jie[i-1]*2;       while (~scanf("%d%d",&n,&m))       {              if (!n && !m) break;               memset(point,0,sizeof(point));              num=0;              for (j=0;j<n;j++)                {                     scanf("%s",s);                      len=strlen(s);                     h=0;                     for (i=0;i<len;i++)                     {                            if (!point[h].son[s[i]-'0'])                                 point[h].son[s[i]-'0']=++num;                             h=point[h].son[s[i]-'0'];                      }                     point[h].d+=_2jie[j];                                }              while (m--)              {                     scanf("%s",s);                     len=strlen(s);                     h=0;                     for (i=0;i<len;i++)                     {                            if (!point[h].son[s[i]-'0'])                                 point[h].son[s[i]-'0']=++num;                              h=point[h].son[s[i]-'0'];                            if (point[h].w) break;                     }                     point[h].w=true;              }              while (!myqueue.empty()) myqueue.pop();              for (i=0;i<2;i++)                 if (point[0].son[i]) myqueue.push(point[0].son[i]);              num=1;              point[0].n=1;              useful[1]=0;              while (!myqueue.empty())              {                     h=myqueue.front();                     myqueue.pop();                     if (point[point[h].fail].w) point[h].w=true;                     if (point[h].w) continue;                     point[h].d|=point[point[h].fail].d;                     if (point[h].d)                      {                             point[h].n=++num;                             useful[num]=h;                     }                     for (i=0;i<2;i++)                     {                             k=point[h].fail;                             while (k && !point[k].son[i]) k=point[k].fail;                             point[point[h].son[i]].fail=point[k].son[i];                             if (!point[h].son[i])                                 point[h].son[i]=point[k].son[i];                             else                                 myqueue.push(point[h].son[i]);                     }              }              memset(dis,0,sizeof(dis));              for (i=1;i<=num;i++)              {                      memset(used,0,sizeof(used));                     myqueue.push(useful[i]);                     used[useful[i]]=1;                     while (!myqueue.empty())                     {                             h=myqueue.front();                             myqueue.pop();                             if (point[h].w) continue;                             if (point[h].n) dis[i][point[h].n]=used[h]-1;                             for (j=0;j<2;j++)                               if (!used[point[h].son[j]])                               {                                     used[point[h].son[j]]=used[h]+1;                                     myqueue.push(point[h].son[j]);                               }                      }                                   }              goal=_2jie[n]-1;              memset(dp,0,sizeof(dp));              dp[1][0]=1;              while (n--)              {                     for (i=1;i<=num;i++)                        for (k=0;k<goal;k++)                           if (dp[i][k])                           for (j=1;j<=num;j++)                           if (dis[i][j])                           {                                  x=k|point[useful[j]].d;                                  if (!dp[j][x] || dp[j][x]>dp[i][k]+dis[i][j])                                     dp[j][x]=dp[i][k]+dis[i][j];                           }              }              ans=oo;              for (i=1;i<=num;i++)                if (dp[i][goal] && dp[i][goal]<ans) ans=dp[i][goal];              printf("%d\n",ans-1);                     }       return 0;}