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

       先用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 long
using 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;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值