📘 教案 04:动态规划(Dynamic Programming, DP)
1. 问题定义
动态规划用于解决一类问题:
最优子结构 + 重叠子问题
典型目标:
- 求最小值 / 最大值
- 求方案数
- 求可行性
2. 核心思想
动态规划的本质:
将复杂问题分解为子问题,并保存子问题结果,避免重复计算
3. 核心术语(必须讲清)
3.1 最优子结构(Optimal Substructure)
定义:
一个问题的最优解可以由其子问题的最优解构成
例子:
最短路径:
$[
dist(A \to C) = dist(A \to B) + dist(B \to C)
]
3.2 重叠子问题(Overlapping Subproblems)
定义:
子问题会被多次重复计算
例子(斐波那契):
text
f(n) = f(n-1) + f(n-2)
会重复计算:
text
f(n-2), f(n-3), ...
3.3 状态(State)
定义:
描述子问题的变量
示例:
dp\[i\]=前 i 个元素的最优解\]\[ dp\[i\] = \\text{前 i 个元素的最优解} \]\[dp\[i\]=前 i 个元素的最优解
3.4 状态转移(State Transition)
定义:
从子问题推导当前问题的关系
示例:
dp\[i\]=dp\[i−1\]+dp\[i−2\]\]\[ dp\[i\] = dp\[i-1\] + dp\[i-2\] \]\[dp\[i\]=dp\[i−1\]+dp\[i−2\]
3.5 边界条件(Base Case)
定义:
最小子问题的初始值
4. DP 的本质(核心理解)
动态规划不是"算法技巧",而是:
建立状态 + 建立转移方程
5. DP 与递归的关系
递归:
- 自顶向下
- 会重复计算
DP:
- 自底向上
- 记录结果(避免重复)
6. DP 基本步骤(必须背)
Step 1:定义状态
dp\[i\]=?\]\[ dp\[i\] = ? \]\[dp\[i\]=?
Step 2:写转移方程
dp\[i\]=f(dp\[...\])\]\[ dp\[i\] = f(dp\[...\]) \]\[dp\[i\]=f(dp\[...\])
Step 3:确定初始值
Step 4:计算顺序
7. 示例1:斐波那契(入门)
定义:
text
f(n) = f(n-1) + f(n-2)
DP写法:
text
dp[0] = 0
dp[1] = 1
for i = 2 to n:
dp[i] = dp[i-1] + dp[i-2]
时间复杂度:
O(n)\]\[ O(n) \]\[O(n)
8. 示例2:爬楼梯(核心模型)
问题:
每次可以走 1 或 2 步,问有多少种走法
状态定义:
dp\[i\]=走到第 i 阶的方法数\]\[ dp\[i\] = \\text{走到第 i 阶的方法数} \]\[dp\[i\]=走到第 i 阶的方法数
转移:
dp\[i\]=dp\[i−1\]+dp\[i−2\]\]\[ dp\[i\] = dp\[i-1\] + dp\[i-2\] \]\[dp\[i\]=dp\[i−1\]+dp\[i−2\]
本质:
👉 这是"组合问题"
9. 示例3:背包问题(必须讲)
0-1背包
给定:
- 重量 (w[i])
- 价值 (v[i])
- 容量 (W)
状态:
dp\[i\]\[j\]=前 i 个物品,容量 j 的最大价值\]\[ dp\[i\]\[j\] = \\text{前 i 个物品,容量 j 的最大价值} \]\[dp\[i\]\[j\]=前 i 个物品,容量 j 的最大价值
转移:
dp\[i\]\[j\]=max(dp\[i−1\]\[j\],dp\[i−1\]\[j−w\[i\]\]+v\[i\])\]\[ dp\[i\]\[j\] = \\max( dp\[i-1\]\[j\], dp\[i-1\]\[j-w\[i\]\] + v\[i\] ) \]\[dp\[i\]\[j\]=max(dp\[i−1\]\[j\],dp\[i−1\]\[j−w\[i\]\]+v\[i\])
含义:
- 不选第 i 个物品
- 选第 i 个物品
10. 时间复杂度
取决于状态数量:
O(状态数×转移成本)\]\[ O(\\text{状态数} × \\text{转移成本}) \]\[O(状态数×转移成本)
11. 空间优化(进阶)
从二维到一维
text
for i:
for j = W down to w[i]:
dp[j] = max(dp[j], dp[j-w[i]] + v[i])
为什么倒序?
防止重复使用同一物品
12. DP 的分类(重要)
| 类型 | 特点 |
|---|---|
| 线性DP | 一维 |
| 区间DP | 区间转移 |
| 背包DP | 容量限制 |
| 树形DP | 树结构 |
| 状态压缩DP | 位运算 |
13. 常见错误(教学重点)
❌ 错误1:不会定义状态
👉 状态必须"完整描述子问题"
❌ 错误2:转移方程写错
👉 本质是"决策枚举"
❌ 错误3:顺序错
👉 会导致使用未计算值
❌ 错误4:边界条件遗漏
14. DP 与贪心区别
| 项目 | DP | 贪心 |
|---|---|---|
| 是否全局最优 | ✅ | ❌(不一定) |
| 是否回溯 | 有 | 无 |
| 复杂度 | 高 | 低 |
15. 关键结论
- DP = 状态 + 转移
- 本质是"避免重复计算"
- 适用于最优问题
- 设计难点在建模