相对于01背包的区别,物品有无限个,可以无限取。
01背包和完全背包唯一不同就是体现在遍历顺序上,所以本文就不去做动规五部曲了,我们直接针对遍历顺序经行分析!
01背包核心代码:
for(int i = 0; i < weight.size(); i++) { // 遍历物品
for(int j = bagWeight; j >= weight[i]; j--) { // 遍历背包容量
dp[j] = max(dp[j], dp[j - weight[i]] + value[i]);
}
}
01背包内嵌的循环是从大到小遍历,为了保证每个物品仅被添加一次。
而完全背包的物品是可以添加多次的,所以要从小到大去遍历,即:
// 先遍历物品,再遍历背包
for(int i = 0; i < weight.size(); i++) { // 遍历物品
for(int j = weight[i]; j <= bagWeight ; j++) { // 遍历背包容量
dp[j] = max(dp[j], dp[j - weight[i]] + value[i]);
}
}
public static int fullBag2(int m, int bagSize, int[] w, int[] v) {
int[] dp = new int[bagSize+1];
for (int i = 1; i <= bagSize; i++) { // 背包容量
for (int j = 0; j < m; j++) { // 物品
if (i - w[j] >= 0) {
dp[j] = Math.max(dp[i], dp[i - w[j]] + v[j]);
}
}
}
// System.out.println(Arrays.toString(dp));
return dp[bagSize];
}
零钱兑换 可以转化成一个完全背包问题。
即, 装满 amount 大小的 “背包”,有多少种装法。
动规五部曲:
先来看 外层for循环遍历物品(钱币),内层for遍历背包(金钱总额)的情况。
for (int i = 0; i < coins.size(); i++) { // 遍历物品
for (int j = coins[i]; j <= amount; j++) { // 遍历背包容量
dp[j] += dp[j - coins[i]];
}
}
假设:coins[0] = 1,coins[1] = 5。
那么就是先把1加入计算,然后再把5加入计算,得到的方法数量只有{1, 5}这种情况。而不会出现{5, 1}的情况。
所以这种遍历顺序中dp[j]里计算的是组合数!
如果把两个for交换顺序,代码如下:
for (int j = 0; j <= amount; j++) { // 遍历背包容量
for (int i = 0; i < coins.size(); i++) { // 遍历物品
if (j - coins[i] >= 0) dp[j] += dp[j - coins[i]];
}
}
背包容量的每一个值,都是经过 1 和 5 的计算,包含了{1, 5} 和 {5, 1}两种情况。
此时dp[j]里算出来的就是排列数!
即,
外层遍历物品,内层遍历背包,即求组合数。
外层遍历背包,内层遍历物品,即求排列数。
class Solution {
public int change(int amount, int[] coins) {
int[] dp = new int[amount+1];
dp[0] = 1;
for (int i=0; i<coins.length; i++) {
for (int j=coins[i]; j<=amount; j++) {
dp[j] += dp[j - coins[i]];
}
}
return dp[amount];
}
}
这道题和上一题的核心思路是一样的,只不过此题的结果中需要考虑元素的顺序,那么就是求排列数。
外层遍历物品,内层遍历背包,即求组合数。
外层遍历背包,内层遍历物品,即求排列数。
那么遍历顺序就需要变一变
外层遍历背包 target,内层遍历物品(nums)
class Solution {
public int combinationSum4(int[] nums, int target) {
int[] dp = new int[target+1];
dp[0] = 1;
for (int j = 0; j <= target; j++) {
for (int i = 0; i < nums.length; i++) {
if (j >= nums[i]) {
dp[j] += dp[j - nums[i]];
}
}
// System.out.println(Arrays.toString(dp));
}
return dp[target];
}
}