先说完全背包的定义:就是在01背包的基础上所有的物品都有无数个。
如何模拟完全背包?
其实如果会01背包的话,只需要再遍历物品的for循环下,进行一次容量从当前遍历物品重量到最大容量的模拟,本质上还是比大小(取与不取的问题)
完整代码:
function test_completePack1() {
let weight = [1, 3, 5]
let value = [15, 20, 30]
let bagWeight = 4
let dp = new Array(bagWeight + 1).fill(0)
for(let i = 0; i <= weight.length; i++) {
for(let j = weight[i]; j <= bagWeight; j++) {
dp[j] = Math.max(dp[j], dp[j - weight[i]] + value[i])
}
}
console.log(dp)
}
接下来看几道由01变成完全背包的例题:
例题1:
求背包到达指定容量的组合方式数量?
这题递推公式其实跟01背包是一样的,只是遍历方式变成了顺序遍历,使其变成物品数量不限!
完整代码:
/**
* @param {number} amount
* @param {number[]} coins
* @return {number}
*/
var change = function(amount, coins) {
let dp=Array(amount+1).fill(0)
dp[0]=1
for(let i=0;i<coins.length;i++){
for(let j= coins[i];j<=amount;j++){
dp[j]+=dp[j-coins[i]]
}
console.log(dp)
}
return dp[amount]
};
例题2:
求背包到达指定容量的排列方式数量?
同样是在无限物品数量的条件下,我们都知道在组合的基础上求排列是较容易实现得。
所以我们可以先遍历容量再进行物品遍历这样物品就可以实现出现顺序不一样!
如果求组合数就是外层for循环遍历物品,内层for遍历背包。
如果求排列数就是外层for遍历背包,内层for循环遍历物品。
如果把遍历nums(物品)放在外循环,遍历target的作为内循环的话,举一个例子:计算dp[4]的时候,结果集只有 {1,3} 这样的集合,不会有{3,1}这样的集合,因为nums遍历放在外层,3只能出现在1后面!
所以本题遍历顺序最终遍历顺序:target(背包)放在外循环,将nums(物品)放在内循环,内循环从前到后遍历。
完整代码:
/**
* @param {number[]} nums
* @param {number} target
* @return {number}
*/
var combinationSum4 = function(nums, target) {
let dp = Array(target+1).fill(0)
dp[0]=1
for(let j=0;j<=target;j++){
for(let i=0;i<nums.length;i++){
if(j>=nums[i]){
dp[j]+=dp[j-nums[i]]
}
}
}
return dp[target]
};