每天学一个算法--动态规划(Dynamic Programming, DP)

📘 教案 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背包

给定:

  • 重量 (wi)
  • 价值 (vi)
  • 容量 (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. 关键结论


  1. DP = 状态 + 转移
  2. 本质是"避免重复计算"
  3. 适用于最优问题
  4. 设计难点在建模
相关推荐
先吃饱再说10 小时前
判断回文字符串,从一行代码到双指针优化
算法
黄敬峰12 小时前
深入理解算法核心:从递归思想、数组扁平化到快速排序
算法
得物技术14 小时前
从狂野代码到按目标生产:得物推荐 AI Harness 的工程化实践|AICon 演讲整理
人工智能·算法·架构
AI小老六17 小时前
SkillOpt 架构拆解:把 Skill 文本当参数,用执行轨迹训练 Agent
后端·算法·ai编程
胡萝卜术18 小时前
从“分数打架”到“排名投票”:为什么你的ChatBI必须用RRF?
算法·设计模式·面试
Asize18 小时前
初识DFS 与 BFS:递归、队列与图遍历
算法
罗西的思考1 天前
机器人 / 强化学习】HIL-SERL:人类在环驱动的具身智能进化框架
人工智能·算法·机器学习
美团技术团队1 天前
LongCat 开源 VitaBench 2.0:长期动态智能体基准新标杆
人工智能·算法
To_OC2 天前
LC 207 课程表:刚学图论那会儿,我连这是拓扑排序都没看出来
javascript·算法·leetcode