This commit is contained in:
parent
8dc3a66883
commit
b2dda568e2
@ -201,3 +201,96 @@ void complete_knapsack_problem_1d() {
|
||||
- 一种特殊情况是 `dp[0]`,它表示组合成总金额为 `0` 的组合数,我们必须把它赋值为 `1`,这是因为当我们执行 `dp[j] += dp[j - coins[i]]` 的时候,如果 `j == coins[i]` 那么显然应该自增 `1`。
|
||||
- 看看能不能不初始化第一层,我们直接删掉代码试试发现可以,那就不初始化第一层。
|
||||
- 遍历顺序都是从前向后
|
||||
|
||||
### [377. 组合总和 Ⅳ](https://leetcode.cn/problems/combination-sum-iv/)
|
||||
|
||||
这道题我们要先分清楚组合和排列。
|
||||
|
||||
`(1, 2)` 和 `(2, 1)` 是不同的排列,同样的组合。
|
||||
|
||||
本题求的是排列数。
|
||||
|
||||
**如果求组合数就是外层 for 循环遍历物品,内层 for 遍历背包;**
|
||||
|
||||
**如果求排列数就是外层 for 遍历背包,内层 for 循环遍历物品。**
|
||||
|
||||
- `dp[i]` 为从 0 ~ j 中选取排列,凑成 `i` 的排列数
|
||||
- `dp[i] += dp[i - nums[j]]`
|
||||
- `dp[0] = 1` 其它为 `0`
|
||||
- 都从前向后
|
||||
|
||||
### [70. 爬楼梯](https://leetcode.cn/problems/climbing-stairs/)
|
||||
|
||||
本题求的是排列数,因此外循环遍历背包容量,内循环遍历物品。
|
||||
|
||||
- `dp[i]` 为爬到第 `i` 阶的排列个数
|
||||
- `dp[i] += dp[i - nums[j]]`
|
||||
- `dp[0] = 1` 其它为 `0`
|
||||
- 都是从前往后
|
||||
|
||||
### [322. 零钱兑换](https://leetcode.cn/problems/coin-change/)
|
||||
|
||||
本题求的是组合数,因此外循环遍历物品,内循环遍历背包容量。
|
||||
|
||||
- `dp[j]` 为凑成金额 `j` 所需的最少硬币数
|
||||
- `dp[j] = min{dp[j - coins[i]] + 1, dp[j]}`
|
||||
- `dp[0] = 0` 其它为 `INT_MAX`
|
||||
- 都是从前往后
|
||||
|
||||
### [279.完全平方数](https://leetcode.cn/problems/perfect-squares/)
|
||||
|
||||
本题求的是组合数,因此外循环遍历物品,内循环遍历背包容量。
|
||||
|
||||
- `dp[j]` 为能凑成 `j` 的最少完全平方数的个数
|
||||
- `dp[j] = min{dp[j - i * i] + 1, dp[j]}`
|
||||
- `dp[0] = 0` 其它为 `INT_MAX`
|
||||
- 都是从前往后
|
||||
|
||||
## 多重背包
|
||||
|
||||
和 01 背包的区别在于,01 背包的每个元素只能用一次,而多重背包的每个物品能用 `ki` 次。
|
||||
|
||||
解决方法也很简单,把多重背包展开:
|
||||
|
||||
| | Weight | Value | Numbers |
|
||||
| :----: | :----: | :---: | :-----: |
|
||||
| Item 0 | 1 | 15 | 2 |
|
||||
| Item 1 | 3 | 20 | 3 |
|
||||
| Item 2 | 4 | 30 | 2 |
|
||||
|
||||
可以展开成这样的 01 背包:
|
||||
|
||||
| | Weight | Value |
|
||||
| :----: | :----: | :---: |
|
||||
| Item 0 | 1 | 15 |
|
||||
| Item 1 | 1 | 15 |
|
||||
| Item 2 | 3 | 20 |
|
||||
| Item 3 | 3 | 20 |
|
||||
| Item 4 | 3 | 20 |
|
||||
| Item 5 | 4 | 30 |
|
||||
| Item 6 | 4 | 30 |
|
||||
|
||||
```cpp
|
||||
void multi_knapsack_2d() {
|
||||
vector<int> weight = {1, 3, 4};
|
||||
vector<int> value = {15, 20, 30};
|
||||
vector<int> nums = {2, 3, 2};
|
||||
int knapsackWeight = 10;
|
||||
|
||||
// 展开
|
||||
for (int i = 0; i < nums.size(); i++) {
|
||||
while (nums[i] > 1) { // nums[i]保留到1,把其他物品都展开
|
||||
weight.push_back(weight[i]);
|
||||
value.push_back(value[i]);
|
||||
nums[i]--;
|
||||
}
|
||||
}
|
||||
|
||||
vector<int> dp(knapsackWeight + 1, 0);
|
||||
for (int i = 0; i < weight.size(); i++) { // 遍历物品
|
||||
for (int j = knapsackWeight; j >= weight[i]; j--) { // 遍历背包容量
|
||||
dp[j] = max(dp[j], dp[j - weight[i]] + value[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
Loading…
Reference in New Issue
Block a user