目录
完全背包
①定义:有N件物品和一个最多能背重量为W的背包。第i件物品的重量是weight[i],得到的价值是value[i] 。每件物品都有无限个(也就是可以放入背包多次),求解将哪些物品装入背包里物品价值总和最大
②与01背包的区别:每件物品可以重复使用
③遍历顺序:遍历背包时不用倒序遍历,因为物品可以重复使用;遍历顺序不用先物品再背包,可以颠倒顺序(只针对纯完全背包问题)
题目链接:518. 零钱兑换 II
思路
①dp数组,dp[j]表示装满容量为j的背包有dp[j]种方法
②递推公式,dp[j] +=dp[j-coins[i]]
③dp数组初始化,dp[0] = 1,其余为0、
④遍历顺序,先物品后背包求出来的是组合数,符合本题要求;先背包后物品求出来的是排列数,不符合本题要求
⑤推导dp数组,推导后可以理解遍历顺序中的组合数和排列数
代码
class Solution {
public:
int change(int amount, vector<int>& coins) {
vector<int> dp(amount + 1, 0);
dp[0] = 1;
for (int i = 0; i < coins.size(); i++) {
// 虽然是正序遍历,但是j不能从0开始
// j从coins[i]开始,这样才放得下当前物品
for (int j = coins[i]; j <= amount; j++) {
dp[j] += dp[j - coins[i]];
}
}
return dp[amount];
}
};
题目链接:377. 组合总和 Ⅳ
思路
与上一题518.零钱兑换Ⅱ相似,只不过该题求的是排列数,所以要先背包后物品
代码
class Solution {
public:
int combinationSum4(vector<int>& nums, int target) {
vector<int> dp(target + 1, 0);
dp[0] = 1;
for (int i = 0; i <= target; i++) { // 遍历背包
for (int j = 0; j < nums.size(); j++) { // 遍历物品
if (i - nums[j] >= 0 && dp[i] < INT_MAX - dp[i - nums[j]]) {
dp[i] += dp[i - nums[j]];
}
}
}
return dp[target];
}
};
总结
①完全背包与01背包的区别在于物品可以无限使用
②遍历背包时不用倒序遍历,之前的倒序遍历是保证每件物品只能使用一次
③先物品后背包的遍历所求的是组合数
④先背包后物品的遍历所求的是排列数