题目
个物品,重量和价值分别存储在数组和数组中,输入总重量,求选出不超过的物品最大总价值。
每个物品只能选择一次。
,均为, 为.
样例输入
4
2 1 3 2
3 2 4 2
5
个物品,重量分别是,价值分别是,揹包重量为.
样例输出
7
选出号物品,刚好装满揹包,且总价值最大,为.
算法1
表示从前个物品(号)中选出重量不超过的总价值。如果不选择第个物品,则;如果选择第个物品,则(不过要注意判断,如果不成立说明揹包装不下第个物品),这样可得递推关系:
其中初始值为。
最终输出。
由于要从更新到,所以复杂度为。
代码1
#include<stdio.h>
#include<math.h>
#define maxn 105
int max(int a, int b){
return (a>b)?a:b;
}
int main(){
int n, W;
int w[maxn], v[maxn];
int dp[maxn][maxn];
while(scanf("%d %d", &n, &W)==2){
for(int i = 1;i <= n;i++){
scanf("%d", w + i);
}
for(int i = 1;i <= n;i++){
scanf("%d", v + i);
}
for(int j = 0;j <= W;j++){
dp[0][j] = 0;
}
for(int i = 1;i <= n;i++){
dp[i][0] = 0;
}
for(int i = 1;i <= n;i++){
for(int j = 1;j <= W;j++){
if(w[i]>j)dp[i][j] = dp[i-1][j];
else
dp[i][j] = max(dp[i-1][j], dp[i-1][j-w[i]]+v[i]);
}
}
printf("%d\n", dp[n][W]);
}
return 0;
}
算法2
如果改变题目对输入数据的约束:
,均为, 为,为.
已知复杂度为,而上述W非常大,这会导致复杂度很高。
不妨改变为前个物品(号)中选出价值为的最小重量,则需要从更新到,然后输出满足的的最大值。所有物品的总价值不会超过,复杂度就降下来了。
如果不选择第i个物品,则dp[i][j]对应从前个物品中选出价值为,即;如果选择第个物品,则对应(记得先判断),这样得到递推关系:
初始值为,。输出满足的的最大值。
#include<stdio.h>
#define maxn 105
#define INF 1000000005 // 所有物品总重最多为10亿
#define maxv 105
int min(int a, int b){
return (a<b)?a:b;
}
int main(){
int n, W;
int v[maxn], w[maxn];
int dp[maxn][maxn * maxv];
int totalvalue, res;
while(scanf("%d", &n)==1){
for(int i = 0;i < n;i++){
scanf("%d", &w[i]);
}
totalvalue = 0;
for(int i = 0;i < n;i++){
scanf("%d", &v[i]);
totalvalue += v[i];
}
scanf("%d", & W);
for(int j = 1;j <= totalvalue;j++){
dp[0][j] = INF;
}
dp[0][0] = 0;
for(int i = 1;i <= n;i++){
for(int j = 0;j <= totalvalue;j++){
if(j>=v[i-1]){
dp[i][j] = min(dp[i-1][j],dp[i-1][j-v[i-1]]+w[i-1]);
}
else dp[i][j] = dp[i-1][j];
}
}
// 输出dp[n][j]中不超过W的最大的j
res = 0;
for(int j = totalvalue;j >= 0;j--){
if(dp[n][j]<=W){
res = j;
break;
}
}
printf("%d\n", res);
}
return 0;
}