poj 2184 01背包变形:体积为负数的处理

今天遇到一题poj2184,大概思路是01背包dp之后把符合要求的最优解统计出来。但是在解01背包的时候遇到一个问题是体积有负数,这样在dp的过程中会遇到两个问题:循环的时候超出体积的范围;压缩空间的时候状态转移方程:dp[v]=max(dp[v],dp[v-c[i]]+w[i]),c[i]为负数时v-c[i]>v,这样按一般的循环的方向从大到下会重复计算。


先看第二个问题,在一般的01背包压缩空间的时候,体积的遍历是从大到小,因为dp[v]=max(dp[v],dp[v-c[i]]+w[i]),当前的dp[v]只取决于比自己小的dp[v-c[i]],所以从大到小遍历时每次dp[v-c[i]]和dp[v]都是上一次的状态。

如果体积为负v-c[i]>v,从大到小遍历dp[v-c[i]]是当前物品的状态,不是上一个,这样就会出错,解决的办法是从小到大遍历。


针对第一个问题,在处理的时候将整个数轴平移,使得原来所有可能的情况都为正。

例如这题,首先计算出数据的范围:

一共100组数,从-1000到1000,那么体积的范围就是-100*1000到100*1000。平移之后我们要处理的数据范围就在0到200000,新的原点变成100000。

初始化变成:

[cpp]  view plain copy
  1. for(int i=0;i<=200000;i++)     dp[i]=-INF;  
  2.   
  3. dp[100000]=0;  

循环变成:

[cpp]  view plain copy
  1. for(int i=1;i<=n;i++)  
  2. {  
  3.     if(s[i]>0)  
  4.     {  
  5.         for(int v=200000;v>=s[i];v--)   //从可能的最大值到最小值  
  6.         {  
  7.            if (dp[v-s[i]]>-INF)  
  8.                 dp[v]=max(dp[v],dp[v-s[i]]+f[i]);  
  9.         }  
  10.     }  
  11.     else  
  12.     {  
  13.         for(int v=0;v-s[i]<=200000;v++)  
  14.         {  
  15.             if (dp[v-s[i]]>-INF)  
  16.                 dp[v]=max(dp[v],dp[v-s[i]]+f[i]);  
  17.         }  
  18.     }  
  19. }  

计算结果要从100000开始遍历,因为100000相当于原来的0

[cpp]  view plain copy
  1. int nMax=0;  
  2. for(int v=100000;v<=200000;v++)  
  3.     if(dp[v]>=0)  
  4.         nMax=max(nMax,dp[v]+v-100000);  

这题还有一种解决方法:把物品的体积全部加1000,使它们都大于0,然后dp的时候用一个数组记录dp[i][v]时多加了几个1000,最后在结果里减去就行了。这个做法有个需要注意的地方是状态转移变成:

 for(int i=1;i<=n;i++)
            for(int v=sum;v>=s[i];v--)//tot记录多加的1000
                if(dp[v]-tot[v]*1000 <
                   dp[v-s[i]]+f[i]-(1+tot[v-s[i]])*1000)
                {
                    dp[v]=dp[v-s[i]]+f[i];
                    tot[v]=tot[v-s[i]]+1;
                }

而不是

[cpp]  view plain copy
  1. if(dp[v]<dp[v-s[i]]+f[i])  
  2. {  
  3.     dp[v]=dp[v-s[i]]+f[i];  
  4.     tot[v]=tot[v-s[i]]+1;  
  5. }  


因为这时的最大值是某个v+dp[v]-tot[v]*1000,v一定的情况下dp[v]-tot[v]*1000表示的才是最大值,虽然这个最大值的意义不好理解。。


这题的第二种解法只是看结题报告粗浅的理解下,动态规划真是非常神奇。。。。


原文来自:

http://blog.csdn.net/actangy/article/details/7433992

致谢~~~~~~!

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值