这篇page是针对多重背包理论基础所写的。小尼先简单的说明一下什么是多重背包,其实多重背包就是规定有N种物品和一个容量为V的背包。第i种物品对多有Mi件可以使用,每一件耗费的空间是Ci,价值是Wi,求解将哪些物品装入背包种可以使得这些物品耗费的空间总和不超过背包容量,并且价值总和最大。
其实多重背包相对于0-1背包而言就是物品的件数不是唯一的,而是不同的。接下来小尼说明一下分析思路;第一种思路:我们可以考虑将它变化成0-1背包,我们可以思考一下,其实这道题相对于0-1背包问题而言就是数量不同,如果我们在放入数组的时候,我们不将它们看成是同一个背包,而是将它们看成多个数量价格一样的多个物品,这样就是可以直接转化为0-1背包问题了,小尼接下来拉一下这种解法的代码:
public void testMultiPack1(){
// 版本一:改变物品数量为01背包格式
List<Integer> weight = new ArrayList<>(Arrays.asList(1, 3, 4));
List<Integer> value = new ArrayList<>(Arrays.asList(15, 20, 30));
List<Integer> nums = new ArrayList<>(Arrays.asList(2, 3, 2));
int bagWeight = 10;
for (int i = 0; i < nums.size(); i++) {
while (nums.get(i) > 1) { // 把物品展开为i
weight.add(weight.get(i));
value.add(value.get(i));
nums.set(i, nums.get(i) - 1);
}
}
int[] dp = new int[bagWeight + 1];
for(int i = 0; i < weight.size(); i++) { // 遍历物品
for(int j = bagWeight; j >= weight.get(i); j--) { // 遍历背包容量
dp[j] = Math.max(dp[j], dp[j - weight.get(i)] + value.get(i));
}
System.out.println(Arrays.toString(dp));
}
}
小尼简单的跟大家说明一下这里面使用的ArrayList的方法,首先就是add方法,在这里面我们使用的add方法是在我们的weight和value方法中被调用了的,我们这里定义了一个while方法不断地对我们的数组进行一个判断,如果nums.get(i)>1那么我们就会不断地被调用add方法,这样我们的weight数组和value数组就会不断地被往后加入数据,这样我们就可以达到每一个物品的数量都是一,我们只是物品的种类增多,然我我们对dp数组进行判断的时候,我们只需要调用0-1背包的判断就可以了,我们上面的外层循环遍历了物品,我们的内层循环遍历的是背包容量。
接下来,小尼继续说明另外一种方法就是我们可以不断的遍历数量的方法,小尼先拉一下这一段的代码:
public void testMultiPack2(){
// 版本二:改变遍历个数
int[] weight = new int[] {1, 3, 4};
int[] value = new int[] {15, 20, 30};
int[] nums = new int[] {2, 3, 2};
int bagWeight = 10;
int[] dp = new int[bagWeight + 1];
for(int i = 0; i < weight.length; i++) { // 遍历物品
for(int j = bagWeight; j >= weight[i]; j--) { // 遍历背包容量
// 以上为01背包,然后加一个遍历个数
for (int k = 1; k <= nums[i] && (j - k * weight[i]) >= 0; k++) { // 遍历个数
dp[j] = Math.max(dp[j], dp[j - k * weight[i]] + k * value[i]);
}
System.out.println(Arrays.toString(dp));
}
}
}
我们在我们就是加入了第三层循环,其实就是我们做一个判断判断一个值的溢出问题,如果不溢出,那么我们就不断地加入物品并且记录dp,然后我们再做一个max的判断即可。
希望上面的代码和分析可以帮助到小伙伴们~~~