又见01背包
时间限制:
1000 ms | 内存限制:
65535 KB
难度:
3
-
描述
-
有n个重量和价值分别为wi 和 vi 的 物品,从这些物品中选择总重量不超过 W的物品,求所有挑选方案中物品价值总和的最大值。1 <= n <=1001 <= wi <= 10^71 <= vi <= 1001 <= W <= 10^9
-
输入
-
多组测试数据。
每组测试数据第一行输入,n 和 W ,接下来有n行,每行输入两个数,代表第i个物品的wi 和 vi。
输出
- 满足题意的最大价值,每组测试数据占一行。 样例输入
-
4 5 2 3 1 2 3 4 2 2
样例输出
-
7
先来看看背包的容量 1 <= W <= 10^9 背包的容量的最大值为10^9。用背包问题的普通转移方程dp[i][j]=max(dp[i-1][j],dp[i-1][j-
w[i]]+v[i])内存会爆掉,且会超出题目限制的时间。这里需要换方向思考,以往总是在限定的背包容量条件下找出最大总价值,
对于背包的容量太大,而已知的最大总价值确定且数值合适。可以将问题转化为在限定最大总价值条件下找出背包最小容量。即转
移方程为dp[i][j]=min(dp[i-1][j],dp[i-1][j-v[i]]+w[i])且对于此题又有dp[i][j]<=W总重。这样就能很快的求解了。
具体代码如下:
<span style="font-size:18px;">#include<cstdio> #include<cstring> #define min(a,b)(a<b?a:b) int w[110],v[110],dp[10010]; int main() { int n,W,sum,i,j; while(scanf("%d%d",&n,&W)!=EOF) { sum=0; for(i=0;i<n;++i) { scanf("%d%d",&w[i],&v[i]); sum+=v[i]; } for(i=1;i<=sum;++i) dp[i]=999999999;//初始化必须大于10^9,这个地方导致一直wa dp[0]=0; for(i=0;i<n;++i) { for(j=sum;j>=v[i];--j) dp[j]=min(dp[j],dp[j-v[i]]+w[i]); } for(i=sum;i>=0;i--) { if(dp[i]<=W) { printf("%d\n",i); break; } } } return 0; } </span>
-
多组测试数据。