每天学一个算法--动态规划(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. 设计难点在建模
相关推荐
To_OC7 小时前
LC 131 分割回文串:刚学回溯时,我连怎么切字符串都想不明白
javascript·算法·leetcode
旖-旎8 小时前
LeetCode 518:零钱兑换||(完全背包)—— 题解
c++·算法·leetcode·动态规划·背包问题
To_OC9 小时前
LC 42 接雨水:暴力超时卡半天?前后缀数组一用就通了
javascript·算法·leetcode
delishcomcn9 小时前
AI视觉识别+分切算法:电化铝缺陷检测与裁切一体化解锁
人工智能·算法
触底反弹10 小时前
深入理解大模型采样:Temperature、Top-K、Top-P 的原理与实战
人工智能·算法·面试
雪碧聊技术10 小时前
力扣 LCR 091. 粉刷房子 —— 动态规划入门详解
算法·动态规划
CV-Climber13 小时前
检索技术的实际应用
人工智能·算法
hhzz13 小时前
Tiger AI Platform平台中增加人脸识别功能
图像处理·人工智能·算法·计算机视觉·大模型
从零开始的代码生活_14 小时前
C++ 继承详解:访问控制、对象模型、菱形继承与设计取舍
开发语言·c++·后端·学习·算法