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`。
|
- 一种特殊情况是 `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