外观
04 动态规划
本章对应考试中的:P1 矩阵链乘(
2011期末,20 分)、P2 最长公共子序列 LCS(多版本,15~20 分)、P3 投资分配(2011影印)、P4 生产-库存计划(2012影印/2013)、P5 货车分配(2020)、P6 货物分销(merged)、P7 公路广告牌(样题1/试卷3)。动态规划(DP)是本课程分值最高、最容易拿满分的大题。原因是:它的作答格式是完全固定的,资源分配类题目更是"换个数字的同一道题"。本章目标——让你能默写模板、能把表格手工填出来。
核心考点
动态规划(dynamic programming,简称 DP):把一个大问题拆成一系列小问题(子问题),从最小的子问题开始、把每个子问题的答案算出来存进一张表,后面要用就查表,从而避免重复计算,最终拼出大问题的答案。
考试考两种 DP 大题:
- 资源分配型(P3 投资、P4 生产库存、P5 货车、P6 货物):把有限的资源(钱、产量、车、货)分给若干对象,求总收益最大或总成本最小。这四道题是同一个模板的换皮,是性价比最高的考点。
- 经典型(P1 矩阵链乘、P2 LCS、P7 广告牌):每道有自己特定的状态转移方程,但作答框架一样。
所有 DP 大题的得分点都是固定的五样:状态变量、决策变量、状态转移方程、边界条件、手工填表过程。把这五样写全写对就能拿大头分。
从零开始的前置知识
为什么需要"存表"——重复子问题
先看一个不存表会出大问题的例子。斐波那契数定义为
- 算
要算 和 ; - 算
又要算 和 ; - 算
又要算 和 ……
你会发现
DP 的解决办法:开一张表
DP 和分治的区别
分治(详见 02_分治算法.md)也把大问题拆成子问题,但分治的子问题互不相干(例如归并排序左右两半独立),所以不需要存表。DP 的子问题会互相重叠(像上面
什么是"最优子结构"
最优子结构(optimal substructure):大问题的最优解里,包含了它的子问题的最优解。只有具备这个性质,DP 才能用"子问题最优"拼出"大问题最优"。本章所有题都具备这个性质,作答时不必证明,知道这个词的意思即可。
核心理论与方法
动态规划通用四步模板(必背)
任何 DP 大题,按下面四步写,再加手工填表,就齐全了。
第 1 步:设状态变量
状态变量:描述"当前局面"所需要的那几个量。资源分配类题目,状态通常是两样合一:"现在轮到第几个对象"+"手上还剩多少资源"。
写法示例:"设阶段
表示正在考虑第 个对象(项目/月份/公司/零售店);状态 表示此刻还可分配的资源数量。"
第 2 步:设决策变量
决策变量:这一步你要做的选择。
写法示例:"设决策
表示分配给第 个对象的资源量,取值范围 。"
第 3 步:写状态转移方程
状态转移方程(state transition equation):用"子问题的最优值"表示"当前问题的最优值"的等式,是 DP 的核心。资源分配类的通用形式(以求最大收益为例):
逐符号解释:
:从第 个对象开始往后、手上有 份资源时,能取得的最优总收益。这是我们要填进表里的值。 :给第 个对象分配 份资源带来的直接收益(直接查题目给的收益表)。 :把剩下的 份资源留给后面对象,能取得的最优收益(这是已经算好、存在表里的子问题答案)。 :在所有可能的分配量 里,挑使括号内总和最大的那个。
如果题目是求最小成本,就把
第 4 步:写边界条件
边界条件:递推的起点。
写法示例:"边界
(没有对象可分配时,收益为 )。"
第 5 步:手工填表(采分关键)
从边界出发,逆着对象顺序(先算最后一个对象的表
一个最小的演示例子
为了把模板讲透,先做一个最简单的:有 3 万元投给 2 个项目,求最大利润。 收益表(投
| 投资额 | 0 | 1 | 2 | 3 |
|---|---|---|---|---|
| 项目 1 收益 | 0 | 4 | 7 | 9 |
| 项目 2 收益 | 0 | 5 | 8 | 10 |
阶段
先算
| 0 | 1 | 2 | 3 | |
|---|---|---|---|---|
| 0 | 5 | 8 | 10 | |
| 最优 | 0 | 1 | 2 | 3 |
再算
最大利润 12 万元,在
下面四道资源分配大题(P3~P6)就是把"对象个数"和"收益表"换一换,方法一模一样。
答题模板
【状态变量】设阶段 k = 第 k 个对象;状态 s = 当前剩余资源。
【决策变量】设 u = 分配给第 k 个对象的资源量,0 ≤ u ≤ s。
【状态转移方程】f_k(s) = max/min_{0≤u≤s} { g_k(u) + f_{k+1}(s-u) }。
【边界条件】f_{n+1}(s) ≡ 0。
【手工求解】从 f_n 逆序逐表计算(写出每个 max/min 的每一项),到 f_1;
再从 f_1 正向回溯,读出每个对象分到多少。
【结果】最优值 = ___,最优方案 = ___。
【复杂度】状态数 × 每状态决策数 = O(___)。逐题精解
P1 矩阵链乘最优结合(2011期末,20 分)
原题:写出用动态规划求矩阵链乘积
的递推公式、伪代码和时间复杂性,并手工计算 的最优策略与最小开销( 表示 阶矩阵)。
前置:两个矩阵相乘的代价。 一个
为什么加括号顺序会影响总代价。 矩阵连乘满足结合律,结果一样,但乘法次数不同。以
- 先算前两个:
,代价 。 - 先算后两个:
,代价 。
同样的结果,代价相差一倍多。DP 的任务就是找出代价最小的加括号方式。
递推公式。 用
逐符号解释:
伪代码:
text
MatrixChain(d[0..n]):
for l ← 1 to n: m[l][l] ← 0 // 单个矩阵代价为 0
for len ← 2 to n: // 链长从 2 到 n
for l ← 1 to n-len+1:
h ← l+len-1
m[l][h] ← ∞
for i ← l to h-1: // 枚举分界点
cost ← m[l][i] + m[i+1][h] + d[l-1]*d[i]*d[h]
if cost < m[l][h]:
m[l][h] ← cost
s[l][h] ← i // 记录最优分界点,便于回溯加括号
return m[1][n], s时间复杂性: 有
手工计算(
链长 2:
链长 3:
链长 4:
把这些值填进表(行
| 0 | 72 | 36 | 51 | |
| 0 | 24 | 44 | ||
| 0 | 30 | |||
| 0 |
回溯加括号:
易错点:① 合并代价是
P2 最长公共子序列(LCS,多版本)
原题:写出用动态规划求两序列最长公共子序列的递推公式、伪代码和时间复杂性,并手工计算给定序列的 LCS。
前置:子序列 vs 子串。 子序列(subsequence):从原序列里按原顺序挑出若干字符(可以不连续)。例如 ace 是 abcde 的子序列。子串(substring):必须是连续的一段。例如 bcd 是子串,bd 不是子串但是子序列。LCS 求的是公共子序列(两个序列都包含的、可不连续的最长那个)。
递推公式。 设两序列
逐符号解释:当两个当前字符相同(
伪代码:
text
LCS(X[1..m], Y[1..n]):
for i ← 0 to m: c[i][0] ← 0
for j ← 0 to n: c[0][j] ← 0
for i ← 1 to m:
for j ← 1 to n:
if X[i] == Y[j]: c[i][j] ← c[i-1][j-1] + 1
else: c[i][j] ← max(c[i-1][j], c[i][j-1])
return c[m][n]时间复杂性: 表有
版本 A 手工计算(来源 样题2 试卷2,15 分):abcbcc,cacbac。
按递推逐格填表(行是
| c | a | c | b | a | c | ||
|---|---|---|---|---|---|---|---|
| 0 | 0 | 0 | 0 | 0 | 0 | 0 | |
| a | 0 | 0 | 1 | 1 | 1 | 1 | 1 |
| b | 0 | 0 | 1 | 1 | 2 | 2 | 2 |
| c | 0 | 1 | 1 | 2 | 2 | 2 | 3 |
| b | 0 | 1 | 1 | 2 | 3 | 3 | 3 |
| c | 0 | 1 | 1 | 2 | 3 | 3 | 4 |
| c | 0 | 1 | 1 | 2 | 3 | 3 | 4 |
右下角
回溯求出具体 LCS:从右下角出发,相等就取该字符并往左上走,不等就往值大的方向走(上或左):
: c=c→ 取 c,走到; : c≠a,上下相等取上 →; : b≠a→ 往左; : b=b→ 取 b,走到; : c=c→ 取 c,走到; : b≠a→ 往上; : a=a→ 取 a,走到结束。
逆序拼起来得 LCS = acbc(长度 4)。
其它版本结果(方法完全相同,自行填表即可):
- 版本 B(
样题1/试卷1/试卷3):xzyzzyx,zxyyzxz→ LCS 长度 5。 - 版本 C(
试卷4,20 分,要求写出全过程):xzyzzyx,zxyyzxzy→ LCS 长度 5,如xyzzy或zyzzy。
易错点:① 第 0 行、第 0 列要先填 0;② 回溯时若上、左值相等,选哪个都行,可能得到不同但等长的 LCS。
P3 投资分配(2011影印,8 分)
原题:8 万元投给 3 个项目,各项目在不同投资额下的利润见下表,求总利润最大的投资计划(写出状态变量、决策变量、状态转移方程与递推关系式,及手工求解步骤与结果)。
| 投资额(万元) | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 |
|---|---|---|---|---|---|---|---|---|---|
| 项目 1 | 0 | 5 | 15 | 40 | 80 | 90 | 95 | 98 | 100 |
| 项目 2 | 0 | 5 | 15 | 40 | 60 | 70 | 73 | 74 | 75 |
| 项目 3 | 0 | 4 | 26 | 40 | 45 | 50 | 51 | 52 | 53 |
【状态/决策/方程】 阶段
【手工求解】
第一张表
| 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | |
|---|---|---|---|---|---|---|---|---|---|
| 0 | 4 | 26 | 40 | 45 | 50 | 51 | 52 | 53 |
第二张表
(上面九项分别对应给项目 2 投
| 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | |
|---|---|---|---|---|---|---|---|---|---|
| 0 | 5 | 26 | 40 | 60 | 70 | 86 | 100 | 110 | |
| 最优 | 0 | 1 | 0 | 0/3 | 4 | 5 | 4 | 4 | 5 |
第三张表只需
最大值 140 在
【回溯】
【结果】 最大总利润 = 140 万元,方案:项目 1 投 4 万、项目 2 投 4 万、项目 3 投 0 万(
P4 生产-库存计划(2012影印/2013)
原题:未来四个月需求量为 月1=2、月2=3、月3=2、月4=4。每月若生产,固定成本 3 千元;每生产 1 单位成本 1 千元;每月生产批量不超过 6 单位;每单位每月库存费 0.5 千元;第 1 月初与第 4 月末均无库存。求总成本最低的生产与库存安排。
【状态/决策/方程】 阶段
- 库存递推:
( 是第 月需求),且必须 (不能缺货)。 - 单月成本:
。其中 表示"生产了就记 1、没生产记 0"(固定成本只在生产时发生); 是月末库存的存储费。 - 转移方程(求最小):
。 - 边界:
,要求 ,故 。
【一个关键观察,帮你检查答案】 因为月初、月末库存都为 0,总生产量恒等于总需求
【手工求解(逆序填表)】 状态
| 0 | 1 | 2 | 3 | 4 | |
|---|---|---|---|---|---|
| 4 | 3 | 2 | 1 | 0 | |
| 7 | 6 | 5 | 4 | 0 |
(例:
| 0 | 1 | 2 | 3 | 4 | 5 | 6 | |
|---|---|---|---|---|---|---|---|
| 11 | 10 | 7 | 6.5 | 6 | 5.5 | 2 | |
| 最优 | 6 | 5 | 0 | 0 | 0 | 0 | 0 |
(例:
| 0 | 1 | 2 | 3 | 4 | |
|---|---|---|---|---|---|
| 16 | 15 | 14 | 11 | 10.5 | |
| 最优 | 5 | 4 | 3 | 0 | 0 |
(例:
| 2 | 3 | 4 | 5 | 6 | |
|---|---|---|---|---|---|
| 0 | 1 | 2 | 3 | 4 | |
| 当月成本 | 5 | 6.5 | 8 | 9.5 | 11 |
| 16 | 15 | 14 | 11 | 10.5 | |
| 合计 | 21 | 21.5 | 22 | 20.5 | 21.5 |
最小 20.5 在
【回溯】
【结果】 最低总成本 = 20.5 千元,生产策略:月 1 生产 5、月 2 生产 0、月 3 生产 6、月 4 生产 0(靠库存覆盖月 2、月 4 的需求)。验证:固定成本
P5 货车分配(2020,5 分)
原题:5 台货车分给 A、B、C 三个子公司,各公司分到不同车数的年利润见下表,求总利润最大的分配。
| 车辆数 | A | B | C |
|---|---|---|---|
| 0 | 0 | 0 | 0 |
| 1 | 2 | 5 | 5 |
| 2 | 6 | 9 | 6 |
| 3 | 10 | 11 | 11 |
| 4 | 11 | 12 | 12 |
| 5 | 13 | 12 | 13 |
【方程】 阶段 = 子公司(A,B,C),状态
【关键表】 逆序算
| 0 | 1 | 2 | 3 | 4 | 5 | |
|---|---|---|---|---|---|---|
| 0 | 5 | 6 | 11 | 12 | 13 | |
| 0 | 5 | 10 | 14 | 16 | 20 |
【结果】 最大总利润 = 20。存在多个并列最优解,例如:A=0、B=2、C=3(
P6 货物分销(merged,8 分)
原题:一车 6 箱货沿途卸到 4 个零售店,各店卸下不同箱数的利润见下表,求总利润最大的卸货方案。
| 箱数 \ 店 | 1 | 2 | 3 | 4 |
|---|---|---|---|---|
| 1 | 4 | 2 | 3 | 4 |
| 2 | 6 | 4 | 5 | 5 |
| 3 | 7 | 6 | 7 | 6 |
| 4 | 7 | 8 | 8 | 6 |
| 5 | 7 | 9 | 8 | 6 |
| 6 | 7 | 10 | 8 | 6 |
【方程】 阶段 = 零售店
【结果】 按逆序填表(
P7 公路广告牌(样题1/试卷3)
原题:一条由西到东长
公里的公路,可设广告牌的地点为 (已知各点坐标),各点放牌收益 ,要求任两块广告牌距离不小于 3 公里,求总收益最大的放置方案。
【思路】 先把地点按坐标从西到东排序。对每个地点
逐符号解释:不放第
【小例子】 设地点坐标
; ; ; ; 。
最大收益 13(放第 2 点和第 4 点:
【复杂度】 地点已排序时,用双指针求所有
高频陷阱 / 易错点小结
- 四步模板不能漏:状态、决策、转移方程、边界,缺一个扣一块分;手算过程必须写,光写答案不给分。
- 求最小成本时把
换成 (P4),别套错方向。 - 填表顺序:资源分配类逆着对象顺序算(先
后 );矩阵链乘从短链到长链算;LCS 从左上到右下。顺序错了会用到还没算出的值。 - P4 固定成本只在"生产量大于 0"时计入,不生产的月份不算这 3 千元。
- 多个最优解(P5、P6)很常见,写出任意一个并验证总和正确即可。
- 回溯方案别忘做:题目要"安排计划",只给最优值不给方案会扣分。
自测清单
- [ ] 不看书默写"动态规划通用四步模板"(状态/决策/转移方程/边界)。
- [ ] 说清 DP 与分治的区别(子问题是否重叠、要不要存表)。
- [ ] 独立把 P3 投资分配的三张表填出来,得到 140 与方案。
- [ ] 独立把 P4 生产库存做出来,得到 20.5 与生产策略
。 - [ ] 写出矩阵链乘的递推式,并把
算到最优 51。 - [ ] 写出 LCS 递推式,把版本 A 的表填出来并回溯出
acbc。 - [ ] 写出广告牌的递推式并解释
的含义。