学习NOTE 3——动态规划

题外话

之前学了DP ,感觉学了跟学了一样。。。重学一遍,赶紧来写一篇学习NOTE。


下面进入正题。

是什么?

动态规划(Dynamic Programming‌),也就是DP。

DP是一种把复杂问题拆分成重叠子问题、通过填表避免重复计算的算法思想,常用于求最短路、背包问题、编辑距离等。

“公式”:DP=动态规划=拆小问题+记答案+拼大问题

有一些定义:

1.状态(State)

本质:用一组参数完整描述当前子问题。在代码中就是数组的维度和下标。

核心要求:状态必须满足无后效性——给定当前状态后,后续结果只取决于当前状态本身,与怎么到达它的历史路径无关。

设计核心:只提取“影响未来决策”的关键信息,其余全部丢掉。信息不够就加维度,信息冗余就压缩。


状态转移方程(Transition)

本质:从已知状态推导当前状态的递推规则。

推导核心:倒推“最后一步”——想象当前状态已达成,上一步只能来自哪些状态?枚举所有来源,对前置状态值做 max / min / 求和,再叠加当前步的增量。

核心约束:计算当前状态时,所有依赖的前置状态必须已经算完(遍历顺序决定)。


状态是点,转移方程是边,DP就是在DAG上按拓扑序递推。

怎么实现?

第一步:开数组
根据状态定义,确定数组维度和大小。状态有几个参数,数组就开几维,若当前状态只关心上一级,可以用滚动数组

第二步:写转移
按照转移方程,把递推关系写成代码。这一步没有固定格式,完全由方程决定。方程中引用的前置状态,在代码里就是对应的数组元素。

第三步:设起点
在循环开始前,把边界状态的设初值。初值决定了递推从哪里开始。

第四步:定顺序
设计循环的嵌套顺序,确保计算当前状态时,它依赖的所有前置状态都已经有了确定的值。不同类型的 DP 有不同的标准顺序

DP 类型 遍历顺序
线性递推 下标从小到大
二维网格 行和列都从小到大
区间合并 区间长度从小到大,再枚举左端点
树形结构 从叶子向根递归(后序遍历)
集合状压 二进制掩码从小到大

如果状态定义中有“选/不选”且压缩了维度,顺序可能是倒序;如果是一般递推,顺序通常是正序


四步完成,DP 代码就成型了。

有哪些?

为什么要加这个版块呢?我解释一下(是个人都知道啊喂!)。

因为DP有很多种说了跟说了一样),有线性DP、背包DP(01背包、完全背包)、区间DP、状压DP、数位DP、树形DP、动态DP(神一样的存在!) \(\cdots\)

接下来我会分多个NOTE来写每一个DP。

合集链接

posted @ 2026-07-17 21:02  _T_M_T  阅读(9)  评论(0)    收藏  举报