多重背包问题
问题描述
有N种物品和一个容量是V的背包
第i种物品最多有s件,每件体积是v,价值是w
求解将哪些物品装入背包,可使物品体积总和不超过背包容量,且价值总和最大
———————————————————————————————————————
解法一
问题分析:
最外层循环遍历每个商品
中间的循环可以遍历背包的体积
1.如果当前物品的体积大于背包的体积,说明背包装不下这个商品,那么就和装上一件物品的情况一样了,上一件物品是i - 1,所以代码是
dp[i][j] = dp[i - 1][j]
2.如果当前背包的体积大于物品的体积,这个物品可以装下,那么之后要考虑的问题就是装几件了,
首先这几件物品的总体积不能超过背包的总体积,第二是总件数不能超过题目所规定的s[i - 1]
对应的代码为:
for(int k = 0; j - k * v[i - 1] >= 0 && k < s[i - 1]; k++)
dp[i][j]的意思是之前装0~k件中的最大值
dp[i - 1][j - k * v[i - 1]] + k * w[i - 1] 是装k件的值
i - 1的意思是,当前所装的k件i物品,是在第i - 1种物品的基础上装的
j - k * v[i - 1]的意思是,背包需要腾出来k * v[i - 1]的空间用来装这几件
k * w[i - 1] 的意思是这几件的价值
dp[i][j] = Math.max(dp[i][j], dp[i - 1][j - k * v[i - 1]] + k * w[i - 1]);
public class Main {
int N; //物品的种数为N
int V; //背包的容量为V
//v是第i种商品的体积 w是第i种商品的价值 s是第i种商品的个数
public int doubleBag1(int[] v, int[] w, int[] s){
int[][] dp = new int[N + 1][V + 1];
for(int i = 1; i <= N; i++){ //确定是第几个商品
for(int j = 1; j <= V; j++){ //确定体积
if (v[i - 1] > j) dp[i][j] = dp[i - 1][j];
else{
//确定商品个数
for(int k = 0; j - k * v[i - 1] >= 0 && k < s[i - 1]; k++){
dp[i][j] = Math.max(dp[i][j], dp[i - 1][j - k * v[i - 1]] + k * w[i - 1]);
}
}
}
}
return dp[N][V];
}
}
———————————————————————————————————————
解法二
题目分析:
由题目可以知道有有N种物品和一个容量是V的背包,第i种物品最多有s件,每件体积是v,价值是w
如果我们将物品的体积和价值输入v和w数组的时候,不是按种来输入,而是按照件数来输入,就是把N种物品里的每一件都输入进去,那么不是可以转化成0-1背包问题嘛
代码分析:
这里就和0-1背包一样了
大家可以看 最详细的0-1背包问题,小白也可以看懂哦
public class Main {
int N; //物品的种数为N
int V; //背包的容量为V
//基于0-1背包的解法
//v是第i件商品的体积
//w是第i件商品的价值
public int doubleBag2(int[] v, int[] w){
//v.length就是商品的总件数啦
int[][] dp = new int[v.length + 1][V + 1];
for(int i = 1; i <= v.length; i++){
for(int j = V; j > 0; j--) {
if (v[i - 1] > j) dp[i][j] = dp[i - 1][j];
else dp[i][j] = Math.max(dp[i - 1][j], dp[i - 1][j - v[i - 1]] + w[i - 1]);
}
}
return dp[v.length + 1][V + 1];
}
}