---
### **背包问题全面总结**
---
#### **一、基本类型**
1. **0-1背包**
- **特点**:每个物品只能选一次。
- **状态转移**:
- 二维形式:`dp[i+1][c] = max(dp[i][c], dp[i][c-w[i]] + v[i])`
- 一维优化:倒序遍历容量(避免覆盖上一轮结果)
```python
for i in range(n):
for c in range(target, w[i]-1, -1):
dp[c] = max(dp[c], dp[c-w[i]] + v[i])
```
2. **完全背包**
- **特点**:物品可无限次选。
- **状态转移**:
- 二维形式:`dp[i+1][c] = max(dp[i][c], dp[i+1][c-w[i]] + v[i])`
- 一维优化:正序遍历容量(允许重复选择)
```python
for i in range(n):
for c in range(w[i], target+1):
dp[c] = max(dp[c], dp[c-w[i]] + v[i])
```
---
#### **二、常见变种问题**
1. **组合数问题**
- **目标**:计算达到背包容量的不同组合个数。
- **核心方程**:
- 完全背包:`dp[c] += dp[c - x]`
- 初始化:`dp[0] = 1`(空集为一种方案)
- **示例**:零钱兑换 II(LeetCode 518)
```python
dp = [0] * (amount+1)
dp[0] = 1
for x in coins:
for c in range(x, amount+1):
dp[c] += dp[c-x]
```
2. **最小物品数问题**
- **目标**:求达到容量的最少物品数。
- **核心方程**:
- `dp[c] = min(dp[c], dp[c-x] + 1)`
- 初始化:`dp[0] = 0`,其余为 `inf`
- **示例**:零钱兑换(LeetCode 322)
```python
dp = [inf] * (amount+1)
dp[0] = 0
for x in coins:
for c in range(x, amount+1):
dp[c] = min(dp[c], dp[c-x]+1)
```
3. **最大价值问题**
- **目标**:在容量限制下获取最大价值。
- **核心方程**:
- 0-1背包:`dp[c] = max(dp[c], dp[c-w] + v)`
- 初始化:`dp[0] = 0`,其余为 `-inf`(若要求恰好装满)
- **示例**:经典背包问题
```python
dp = [0] * (capacity+1)
for w, v in items:
for c in range(capacity, w-1, -1):
dp[c] = max(dp[c], dp[c-w] + v)
```
---
#### **三、关键技巧**
1. **空间优化**
- 0-1背包 → 倒序遍历容量(防止覆盖)
- 完全背包 → 正序遍历容量(允许重复选)
2. **初始化**
- **组合数**:`dp[0] = 1`
- **最小物品数**:`dp[0] = 0`,其余为 `inf`
- **恰好装满**:`dp[0] = 0`,其余为 `-inf`(最大价值问题)
3. **边界条件**
- 容量需满足 `c >= x` 才能选择物品。
- 注意题目是否允许“不装满”(如初始化全为 0)。
---
#### **四、常见问题解答**
1. **如何区分 0-1背包和完全背包?**
- 看物品是否可重复选。
- 遍历顺序:0-1背包倒序,完全背包正序。
2. **如何处理恰好装满?**
- 初始化时,仅 `dp[0] = 0`(有效状态),其余为 `-inf`(无效状态)。
3. **多维背包问题?**
- 扩展状态维度,如 `dp[c][k]` 表示容量为 `c`、已选 `k` 个物品时的最优解。
---
#### **五、代码模板速查**
| 问题类型 | 代码框架 |
|------------------------|--------------------------------------------------------------------------|
| **0-1背包(最大价值)** | 倒序遍历容量,状态转移取 `max(dp[c], dp[c-w]+v)` |
| **完全背包(组合数)** | 正序遍历容量,状态转移为 `dp[c] += dp[c-x]` |
| **最小物品数** | 正序/倒序取决于背包类型,状态转移取 `min(dp[c], dp[c-x]+1)` |
---
2454

被折叠的 条评论
为什么被折叠?



