您的位置:首页 > 其它

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

2014-08-05 21:54 316 查看
今天遇到一题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;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: