poj 2184 Cow Exhibition(处理负数的01背包)

来源:互联网 发布:js获取div id值 编辑:程序博客网 时间:2024/06/05 11:08

今天遇到一题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。

#include<iostream>#include<cstdio>#include<cstring>#include<algorithm>using namespace std;const int inf=200000;int dp[inf+10];//100*1000*2,表示当s之和达到i时,f之和的最大值int w[110],v[110];int onePack(int n){int i,j,s;for(i=0;i<n;i++){if(w[i]>0){for(j=inf;j>=w[i];j--){//从大向小遍历dp[j]=max(dp[j],dp[j-w[i]]+v[i]);}}else{ //从小向大遍历 for(j=0;j-w[i]<=inf;j++){dp[j]=max(dp[j],dp[j-w[i]]+v[i]);}}}for(s=-inf,i=100000;i<=inf;i++){if(dp[i]>=0){s=max(s,dp[i]+i-100000);}} return s;}int main(){int n,m,i,j;while(~scanf("%d",&n)){memset(w,0,sizeof(w));memset(v,0,sizeof(v));for(i=0;i<=inf;i++){//初始化 dp[i]=-inf; }dp[inf/2]=0;for(i=0;i<n;i++){scanf("%d%d",&w[i],&v[i]);}printf("%d\n",onePack(n));}return 0;} 


0 0
原创粉丝点击