赞
踩
目录
有n件物品(每种物品都只有一件),w[i]表示物品的重量,v[i]表示物品的价值,现有一个容量为V的背包,应该如何选物品使得书包内装的物品的value之和最大呢?
对于第i个物品,有选和不选两种情况
dp[i][j]表示在容量为j的情况下选取i个物品的最大value值
核心代码:
- for(i=0;i<n;i++)
- for(j=V;j>=w[i];j--)
- dp[i][j]=max(dp[i-1][j],dp[i-1][j-w[i]]+v[i]);
核心代码:
- for(i=0;i<n;i++)
- for(j=V;j>=w[i];j--)
- dp[j]=max(dp[j],dp[j-w[i]]+v[i]);
注意:
用二维数组存的话j的枚举是顺序还是逆序都没有关系
但是用一维数组存的话j的枚举顺序必须是逆序,即从大到小
举个例子:
V=8
i=1 | i=2 | i=3 | i=4 | |
w[i] | 2 | 3 | 4 | 5 |
v[i] | 3 | 4 | 5 | 6 |
如果按照顺序(j从小到大枚举),dp数组初始化为0
当i=1时
dp[2]=max(dp[2],dp[0]+3)=3;
dp[3]=max(dp[3],dp[1]+3)=3;
dp[4]=max(dp[4],dp[2]+3)=6;
dp[5]=max(dp[5],dp[3]+3)=6;
当容量为4时,dp[4]的值为6,它是由dp[3]+3的到的,且dp[3]=3,意思是它实际上选了两次“i=1”这个物品,那么结果显然是错的。而正巧,顺序枚举j正好完全背包问题的解法(每种物品由无穷件)。
但是如果逆序枚举的话:
dp[5]=max(dp[5),dp[3]+3);dp[5]和dp[3]之前都没有出现过,所以dp[5]=3,值是正确的(dp[3]的值的改变是在dp[5]之后)
hdoj2602:Bone Collector 典型的01背包问题
- #include <iostream>
- #include <cmath>
- #include <algorithm>
- #include <queue>
- #include <cstring>
- #define ll long long int
- #define maxn 1005
- using namespace std;
- int v[maxn],w[maxn],dp[maxn];
- int main()
- {
- int t,n,V,i,j,ans;
- scanf("%d",&t);
- while(t--)
- {
- memset(dp,0,sizeof(dp));
- scanf("%d %d",&n,&V);
- for(i=0;i<n;i++)
- scanf("%d",&v[i]);
- for(i=0;i<n;i++)
- scanf("%d",&w[i]);
- for(i=0;i<n;i++)
- for(j=V;j>=w[i];j--)
- dp[j]=max(dp[j],dp[j-w[i]]+v[i]);
- printf("%d\n",dp[V]);
- }
- return 0;
-
- }
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。