贪心与动态规划:从区间调度到状态转移方程
0. 元信息
- 主题路径:
docs/topics/algo-design/subtopics/greedy-and-dp/README.md - 父主题:
algo-design - 主分类:数据结构与算法
- 辅助分类:计算机基础
- 适合对象:掌握递归与回溯、Python 基础数据结构;想系统性建立贪心和 DP 设计能力的学习者
- 建议周期:3~4 周(每周 10~14 小时)
- 前置知识:
recursion-and-backtracking、高中数学(递推、求和)、基本复杂度分析 - 最终目标:能在 35 分钟内独立设计 0/1 背包、LIS、LCS、矩阵链乘的状态与转移;能用一句话证明常见贪心题的正确性或构造反例推翻
1. 学习路线
贪心范式:排序后扫描 + 交换论证
→ 区间调度 / Huffman / 跳跃游戏
→ DP 范式:递归 + memoization
→ 自顶向下 vs 自底向上
→ 0/1 背包 → 完全背包 → 多重背包
→ 序列 DP:LIS / LCS / 编辑距离
→ 区间 DP:矩阵链乘 / 戳气球
→ 状压 DP:TSP / 集合划分
→ 空间优化:滚动数组 / 状态压缩
每一步都跟一道题。贪心要先写 DP,再构造反例;DP 先写二维,再压一维。
2. 阶段周数分配
| 阶段 | 3 周方案 | 4 周方案 | 备注 |
|---|---|---|---|
| 1. 贪心基础 | 1.5 天 | 2 天 | 排序后扫描 + 交换论证 |
| 2. DP 入门 | 2 天 | 2.5 天 | 70 / 198 / 64 / 322 / 300 |
| 3. 0/1 背包与完全背包 | 2 天 | 2.5 天 | 416 / 494 / 518 / 474 |
| 4. 序列 DP | 2 天 | 2.5 天 | 1143 LCS / 72 编辑距离 / 5 / 516 |
| 5. 区间 DP | 1.5 天 | 2 天 | 312 戳气球 / 1039 三角剖分 |
| 6. 状压 DP | 1.5 天 | 2 天 | 464 / 526 / 847 / 1434 |
| 7. 空间优化与综合刷题 | 1.5 天 | 2.5 天 | 滚动数组 + AtCoder DP Contest |
每天 1.5~2 小时。3 周方案聚焦前 5 阶段;4 周方案多一周做综合刷题与空间优化。
3. 九阶段表(精简)
3.1 核心知识
- 贪心:每步取局部最优,能证明全局最优;不能证明时退到 DP。
- DP 三要素:状态定义、转移方程、初始化(含边界)。
- DP 优化方向:去掉无效维度、滚动数组、单调队列 / 单调栈。
- 0/1 背包 vs 完全背包:状态相同,转移遍历顺序不同(0/1 逆序、完全背包正序)。
- 序列 DP:状态维度常是下标 i 与 j;LIS 用 patience sorting 可达 O(n log n)。
- 区间 DP:状态维度是区间 [l, r];从小到大枚举区间长度。
- 状压 DP:用 bitmask 表示集合;n ≤ 20 比较合适。
3.2 实践产出
- 8 道贪心(435 无重叠区间、253 会议室 II、55 跳跃游戏、45 跳跃游戏 II、134 加油站、406 根据身高重建队列、621 任务调度器、763 划分字母区间);
- 25 道 DP,含:
- 5 道入门(70 爬楼梯、198 打家劫舍、64 最小路径和、322 零钱兑换、300 LIS);
- 8 道基础(416 分割等和子集、494 目标和、518 零钱兑换 II、1143 LCS、72 编辑距离、5 最长回文子串、516 最长回文子序列、647 回文子串);
- 6 道区间 DP(312 戳气球、1039 多边形三角剖分、1547 切棍子的最小成本、1000 合并石头的最低成本、1771 由子序列构造的最长回文、1312 字符串构造);
- 6 道状压 DP(464 我能赢吗、526 优美的排列、847 访问所有节点的最短路径、1434 每个人戴不同帽子的方式、1799 N 次操作后的最大分数、1349 参加考试的最大学生数)。
3.3 可观察学会标准
- 不看答案在 25 分钟内写出 0/1 背包的状态转移;
- 能在 10 分钟内构造 435 / 55 / 134 等题的反例(如果是错题);
- 能独立推导 312 戳气球的状态维度
dp[l][r]; - 能解释为什么 TSP 状压用
dp[mask][i]而不是dp[mask]。
4. 第一周(每天 1.5~2 小时)
Day 1 约定:本计划使用 Python 3.10+。统一格式:
python -X dev -W error -m py_compile foo.py;测试用pytest;题号统一以 LeetCode 编号为准。所有代码放进algo-design/greedy-dp/week<N>/目录;每个题目单独.py文件,配套notes/<problem>.md含状态转移方程、复杂度推导、反例构造(贪心题)。
| 日 | 任务 | 当天交付 | 自检 |
|---|---|---|---|
| Day 1 | 装 Python 3.11 + pytest + ruff;贪心入门 3 道:435 无重叠区间、55 跳跃游戏、134 加油站 | week1/day1/greedy_intro.py + 反例记录 | pytest week1/day1/test_greedy.py 3 passed;LeetCode 3/3 AC;为 55 题写 3 个反例验证贪心正确性 |
| Day 2 | 贪心 5 道:253 会议室 II、45 跳跃游戏 II、406 根据身高重建队列、621 任务调度器、763 划分字母区间 | week1/day2/greedy_more.py | pytest week1/day2/test_greedy.py 5 passed;LeetCode 5/5 AC;每题记录排序键与正确性一句话证明 |
| Day 3 | DP 入门 5 道:70 爬楼梯、198 打家劫舍、64 最小路径和、322 零钱兑换、300 LIS | week1/day3/dp_intro.py | pytest week1/day3/test_dp.py 5 passed;LeetCode 5/5 AC;为 300 LIS 写 O(n log n) patience sorting 优化 |
| Day 4 | 0/1 背包 + 完全背包 4 道:416 分割等和子集、494 目标和、518 零钱兑换 II、474 一和零 | week1/day4/knapsack.py | pytest week1/day4/test_knapsack.py 4 passed;LeetCode 4/4 AC;画二维表填 3×3 + 滚动数组箭头方向 |
| Day 5 | 序列 DP 4 道:1143 LCS、72 编辑距离、5 最长回文子串、516 最长回文子序列 | week1/day5/seq_dp.py | pytest week1/day5/test_seq_dp.py 4 passed;LeetCode 4/4 AC;为 72 题写二维表(i=0..3, j=0..3)填值过程 |
| Day 6 | 区间 DP 入门:312 戳气球、1039 多边形三角剖分;画区间 DP 的状态维度 dp[l][r] | week1/day6/interval_dp.py | pytest week1/day6/test_interval.py 2 passed;LeetCode 2/2 AC;记录区间长度 len=2..n 的枚举顺序 |
| Day 7 | 步骤 A:完成「最长回文子序列」(516)的完整推导(暴力 → memo → 二维 DP → 滚动数组);步骤 B:补齐 4 类边界(空串 / 单字符 / 全相同 / 全相反) | week1/day7/lps.py + 4 类边界日志 | pytest -k test_lps 4 个用例全过;每类边界用例的输入/期望/实际写到 notes/week1-day7.md |
Day 7 执行次序
步骤 A —— LPS 完整版(60~90 分钟)
- 写暴力递归
lps(s, i, j); - 加 memo → 自顶向下 DP;
- 改自底向上二维 DP
dp[i][j]; - 压一维滚动数组;
- 对比四版耗时。
步骤 B —— 4 类边界用例(30~45 分钟)
| # | 用例 | 期望行为 | 验证命令 |
|---|---|---|---|
| B1 | 空串 "" | 返回 0 | pytest -k test_empty |
| B2 | 单字符 "a" | 返回 1 | pytest -k test_single |
| B3 | 全相同 "aaaa" | 返回 4 | pytest -k test_all_same |
| B4 | 全相反 "abcd" | 返回 1 | pytest -k test_all_distinct |
Day 7 当天必完成步骤 A;步骤 B 至少完成 B1、B3。
5. 阶段通用验收(精简)
- 不看答案重写 25 道 DP 模板;
- 用自己的话解释贪心和 DP 的适用边界;
- 画出每道 DP 题的状态转移表(二维表填 3×3);
- 测试空数据、单元素、相同元素、相反元素四档;
- 至少准备 3 组自定义数据贴出实际输出;
- 记录每题时间空间复杂度,并指出哪一维能压缩;
- 能给现有 DP 加维度(如加一维费用)或压维度(如二维 → 一维)。
6. 最终验收
-
独立实现:25 道 DP(5 入门 + 8 基础 + 6 区间 + 6 状压)+ 8 道贪心(含 Huffman、活动选择、Jump Game);
-
至少完成 33 道题(LeetCode / AtCoder / Codeforces),分布建议:
子阶段 题目数量 难度分布 平台建议 贪心基础 8 道 4 Easy + 3 Medium + 1 Hard LeetCode 435 / 253 / 55 / 45 / 134 / 406 / 621 / 763 DP 入门 5 道 4 Easy + 1 Medium LeetCode 70 / 198 / 64 / 322 / 300 0/1 背包与完全背包 4 道 1 Easy + 3 Medium LeetCode 416 / 494 / 518 / 474 序列 DP 8 道 2 Easy + 5 Medium + 1 Hard LeetCode 1143 / 72 / 5 / 516 / 647 + 3 进阶 区间 DP 6 道 1 Easy + 4 Medium + 1 Hard LeetCode 312 / 1039 / 1547 / 1000 / 1771 / 1312 状压 DP 6 道 1 Easy + 4 Medium + 1 Hard LeetCode 464 / 526 / 847 / 1434 / 1799 / 1349 约束:至少 12 道达到 Medium,至少 5 道达到 Hard / AtCoder 400+;DP 题必须覆盖背包、序列、区间、状压四种类型。
-
完成 1 个综合 Python 项目(自带 README,能被他人按文档复现);
-
能用 15 分钟讲清贪心证明三件套(交换论证 / 反例构造 / 拟阵)、DP 三要素、0/1 vs 完全背包遍历顺序、滚动数组方向、状压状态数估算
n × 2^n。
7. 综合项目
首选:算法可视化桌面工具(必做:CLI 输入 + 输出 + 可选 GUI)。
备选:自动评测器(从 LeetCode / AtCoder 拉指定题目的测试用例,本地批量跑、对比时间、生成错题本)。
备选:算法题模板生成器(给定题型关键词 → 输出 Python 模板:状态定义 / 转移 / 初始化 / 空间优化)。
算法可视化工具必做要求:
- 输入:stdin 接收算法名(
merge_sort/quick_sort/lcs/coin_change/n_queens/tsp)+ 数据集; - 输出:必输出(1)算法过程的文字回放(每一步状态、当前下标、做了什么操作);(2)时间 / 空间复杂度 + 实际耗时;(3)解的总数 / 解集;(4)状态转移表(二维 DP 填表过程);
- 算法:必须用至少 3 种范式(递归 + 分治 + DP 或贪心 + DP + 状压);
- 进阶可选:ASCII 动画(终端 curses 逐步展开)、PyGame GUI、可对比两种算法的可视化(如 DFS vs 贪心)。
任何综合项目都必须包含:
- 需求说明(含输入输出约定);
- 数据结构与算法选择理由(为何用 DP、为何选这种状态);
- 核心模块说明(Solver / Recorder / Renderer 三层);
- 模块化源码(每题单独文件 + 公共 base class);
- 边界测试(n=0, 1, 2, 8, 10 + 空数据 + 极端数据);
- 运行说明(
Makefile或清晰的python -m命令); - README(项目介绍、运行步骤、目录结构、复盘);
- notes/ 规范:
| 文件 | 内容 |
|---|---|
notes/design.md | 数据结构选择理由、状态定义、转移方程、空间优化方向 |
notes/test.md | 每组测试数据的输入 / 期望输出 / 实际输出 / 通过情况 |
notes/retrospective.md | 用时、难点、收获、下一步 |
notes/state-tables/ | 至少 5 道 DP 题的二维状态转移表(手画 + 程序填表截图) |
notes/complexity-proofs/ | 每题的复杂度推导(T(n) + 滚动数组方向论证) |
notes/greedy-counters/ | 至少 3 道疑似贪心题的反例构造(含输入 → 反例 → 错误输出) |
notes/dp-templates/ | 5 个 DP 模板(背包 / 序列 / 区间 / 状压 / 滚动数组) |
notes/edge-cases.md | 4 类边界用例的输入 / 期望 / 实际 |
本主题贡献
3 职责
- 给出可证明的贪心策略 —— 区间调度按”结束时间”排序(活动选择)、跳跃游戏维护”最远可达下标”、Huffman 用优先队列每次合并最小两个;并能用交换论证(找等价代换的”反序对”)或拟阵(独立集 + 交换性质)证明正确性,不能证则必须退到 DP。
- 把 DP 拆成三要素 —— 状态定义(“做完第 i 步还剩什么”)、转移方程(前驱状态 + 当前一步的递推)、初始化(含
dp[0]与dp[i][0]边界);并在二维 → 一维滚动数组时画箭头验”旧值不被新值覆盖”。 - 用状态压缩处理维度爆炸 —— 0/1 背包 vs 完全背包的遍历方向(0/1 逆序、完全背包正序)、LIS 用 patience sorting 压到 O(n log n) 单调栈、TSP 状压用
dp[mask][i]估算n × 2^n状态数。
4 交付物
- 33 道题解(25 DP + 8 贪心)+ 4 类边界用例日志(空 / 单元素 / 全相同 / 全相反)。
- 算法可视化工具(CLI → DP 填表过程 + 贪心 vs DP 反例对比 + 状态转移表二维填表截图)。
- 至少 5 道 DP 题的二维状态转移表(70 爬楼梯 / 198 打家劫舍 / 322 零钱兑换 / 1143 LCS / 72 编辑距离)落
notes/state-tables/+ 至少 3 道疑似贪心题的反例构造(含输入 → 反例 → 错误输出)落notes/greedy-counters/。 - DP 模板 5 件套(0/1 背包 / 序列 DP / 区间 DP / 状压 DP / 滚动数组)落
notes/dp-templates/,每个模板标明”遍历方向”与”压缩维度”。
3 指标
- 35 分钟内独立设计 0/1 背包 / LIS / LCS / 矩阵链乘的状态与转移(覆盖背包、序列、区间、状压四大 DP 范式)。
- 10 分钟内构造 435 / 55 / 134 等疑似贪心题的反例(证明”贪心不是万能”已固化为本能 —— 任何贪心策略先问一句”什么时候会反例”)。
- 二维 dp 压一维后内存下降 ≥ 50%(验证空间优化方向正确;如 198 打家劫舍 O(1) 滚动变量比 O(n) 数组内存少一半)。
| 阶段 | 角色 | 资料 | 链接 | 用法 |
|---|---|---|---|---|
| 1~5 | 经典书 | CLRS《Introduction to Algorithms》第 4 版 | https://mitpress.mit.edu/9780262033848/ | 三大范式(分治 / 贪心 / DP)逐章精读 |
| 1~5 | 进阶书 | Manber《Introduction to Algorithms》 | https://www.cs.arizona.edu/~merlin/Algorithms.pdf | 递归思维训练,按数学归纳讲 |
| 1~5 | 进阶书 | Knuth《The Art of Computer Programming》Vol.1~4A | https://www-cs-faculty.stanford.edu/~knuth/taocp.html | 拿来当字典,遇到细节再查 |
| 1~6 | 刷题平台 | LeetCode | https://leetcode.cn/ | 中文题库;DP / 贪心按 tag 刷 |
| 1~6 | 刷题平台 | Codeforces | https://codeforces.com/ | 模拟赛 + Editorial |
| 1~3 | DP 训练 | AtCoder Educational DP Contest | https://atcoder.jp/contests/dp | 26 题系统性 DP 训练;必跑 |
| 1~6 | Editorial | AtCoder Editorial | https://atcoder.jp/ | ABC/ARC/AGC 公开题解 |
| 1~5 | 范式 | Kleinberg & Tardos《Algorithm Design》 | https://www.cs.princeton.edu/~smattw/ | 范式 + 网络流 + NP 完全;与 CLRS 互补 |
| 3 | 训练营 | Petrozavodsk Camp | https://codeforces.com/groups/c3v4QqHRIy | 高强度团队训练;难题偏多 |
| 1~5 | 框架 | labuladong DP 框架 | https://labuladong.online/algo/ | 中文框架化讲解;先自己写再对照 |
| 1~5 | 图解 | CP-Algorithms DP 章节 | https://cp-algorithms.com/ | 英文图解 + 代码;当字典 |
| 1~6 | 训练 | USACO Guide | https://usaco.guide/ | 美国队训练;按难度递进 |
许可证提示:CLRS 与 Manber 自用学习合理引用;不要复制粘贴 CLRS 课后答案到公开仓库。LeetCode 题面版权见 LeetCode Terms of Service——代码自己写,思路可以分享。CP-Algorithms 是 CC BY-SA。默认做法是读思路后自己重写代码,而不是复制 Editorial。
默认使用顺序:先用 LeetCode 按 tag 刷 30 道建立手感 → 跑 AtCoder Educational DP Contest 26 题 → 选读 CLRS 第 1516 章(DP / 贪心)→ 周末打 Codeforces 模拟赛 → 选读 Manber 第 12 章做归纳思维训练 → 用 labuladong / CP-Algorithms 对照 5 道卡住的题 → 写复盘到 notes/retrospective.md。
8. 推荐开源资料
| 阶段 | 角色 | 资料 | 链接 | 用法 |
|---|---|---|---|---|
| 1~5 | 经典书 | CLRS《Introduction to Algorithms》第 4 版 | https://mitpress.mit.edu/9780262033848/ | 三大范式(分治 / 贪心 / DP)逐章精读 |
| 1~5 | 进阶书 | Manber《Introduction to Algorithms》 | https://www.cs.arizona.edu/~merlin/Algorithms.pdf | 递归思维训练,按数学归纳讲 |
| 1~5 | 进阶书 | Knuth《The Art of Computer Programming》Vol.1~4A | https://www-cs-faculty.stanford.edu/~knuth/taocp.html | 拿来当字典,遇到细节再查 |
| 1~6 | 刷题平台 | LeetCode | https://leetcode.cn/ | 中文题库;DP / 贪心按 tag 刷 |
| 1~6 | 刷题平台 | Codeforces | https://codeforces.com/ | 模拟赛 + Editorial |
| 1~3 | DP 训练 | AtCoder Educational DP Contest | https://atcoder.jp/contests/dp | 26 题系统性 DP 训练;必跑 |
| 1~6 | Editorial | AtCoder Editorial | https://atcoder.jp/ | ABC/ARC/AGC 公开题解 |
| 1~5 | 范式 | Kleinberg & Tardos《Algorithm Design》 | https://www.cs.princeton.edu/~smattw/ | 范式 + 网络流 + NP 完全;与 CLRS 互补 |
| 3 | 训练营 | Petrozavodsk Camp | https://codeforces.com/groups/c3v4QqHRIy | 高强度团队训练;难题偏多 |
| 1~5 | 框架 | labuladong DP 框架 | https://labuladong.online/algo/ | 中文框架化讲解;先自己写再对照 |
| 1~5 | 图解 | CP-Algorithms DP 章节 | https://cp-algorithms.com/ | 英文图解 + 代码;当字典 |
| 1~6 | 训练 | USACO Guide | https://usaco.guide/ | 美国队训练;按难度递进 |
许可证提示:CLRS 与 Manber 自用学习合理引用;不要复制粘贴 CLRS 课后答案到公开仓库。LeetCode 题面版权见 LeetCode Terms of Service——代码自己写,思路可以分享。CP-Algorithms 是 CC BY-SA。默认做法是读思路后自己重写代码,而不是复制 Editorial。
默认使用顺序:先用 LeetCode 按 tag 刷 30 道建立手感 → 跑 AtCoder Educational DP Contest 26 题 → 选读 CLRS 第 1516 章(DP / 贪心)→ 周末打 Codeforces 模拟赛 → 选读 Manber 第 12 章做归纳思维训练 → 用 labuladong / CP-Algorithms 对照 5 道卡住的题 → 写复盘到 notes/retrospective.md。
9. 学习资料汇聚(v0.3)
9.1 背景与动机
Bellman 在 1954 年的 RAND 报告中命名 Dynamic Programming(为避开”研究”在政府语境里的敏感词)。同一时期,Dijkstra、Huffman、Kruskal 把”每步取局部最优”的贪心方法系统化。Cormen 等人在 1990 年的 CLRS 把这两类范式放进了同一本教材并标准化了”状态 / 转移 / 初始化”的写作格式。
行业位置:DP 是中高级面试必考(LeetCode Medium 中 DP 占 1/3);贪心是面试”加分题”(能证明正确性显得有深度)。竞赛里 DP 是 Codeforces Div.2 D/E 题常见类型。一句话总结:贪心 = DP 在”每步只看局部最优且不破坏全局”的特例;DP 是带记忆的递归。
9.2 概念地图
flowchart LR
Greedy[贪心]
SwapArg[交换论证]
CounterEx[反例构造]
DP[动态规划]
State[状态定义]
Trans[转移方程]
Init[初始化]
Opt[空间优化]
Knapsack[0/1 背包]
Sequence[序列 DP]
Interval[区间 DP]
Bitmask[状压 DP]
Greedy --> SwapArg
Greedy --> CounterEx
Greedy --> DP
DP --> State
State --> Trans
Trans --> Init
DP --> Opt
Opt --> Knapsack
Opt --> Sequence
Opt --> Interval
Opt --> Bitmask
核心关系:贪心要先证明(交换论证)或找反例,否则退到 DP;DP 三要素是状态、转移、初始化;空间优化是工程化必经步骤。
9.3 基础知识讲解
9.3.1 经典论文
| 资料 | 影响 | 建议读法 |
|---|---|---|
| Bellman, On the Theory of Dynamic Programming(1954/1957) | DP 起源与最优性原理 | 看”最优性原理”形式化 |
| Huffman, A Method for the Construction of Minimum-Redundancy Codes(1952) | 贪心经典 | 自己写一遍 Huffman 构造 |
| Kruskal, On the Shortest Spanning Subtree of a Graph(1956) | MST 贪心 | 与 Prim 对照看 |
| Edmonds, Paths, Trees, and Flowers(1965) | 一般图匹配与”拟阵”理论 | 看贪心适用条件 |
| Karp, Reducibility Among Combinatorial Problems(1972) | NP 完全问题;划分哪些能 DP 解 | 用来判断是否值得 DP |
9.3.2 经典书籍
| 书 | 影响 | 用法 |
|---|---|---|
| CLRS 第 4 版第 15 章 DP、第 16 章贪心 | 范式标准 | 精读 15.1 |
| Kleinberg & Tardos Algorithm Design 第 6 章 DP、第 7 章贪心 | 设计视角 | 与 CLRS 互补,更强调证明 |
| Roughgarden Algorithms Illuminated 第 3 册 | DP 直觉 | 入门期快速建立 |
| Halim Competitive Programming 3 第 3 章 DP | 竞赛实战 | 当题目反查字典 |
9.3.3 优秀博客
| 资料 | 特点 | 用法 |
|---|---|---|
| AtCoder DP Contest Editorial | 26 题官方题解 | 系统训练用 |
| labuladong DP 框架 | 中文框架 | 当 Cheatsheet |
| CP-Algorithms DP 章节 | 英文图解 + 代码 | 当字典 |
| USACO Guide DP 模块 | 按难度递进 | 长期刷题路线 |
9.3.4 核心人物
| 人物 | 主要影响 | 建议追踪的材料 |
|---|---|---|
| Richard Bellman | DP 命名 + 最优性原理 | 1954 RAND 报告 |
| David Huffman | Huffman 编码 | 1952 论文 |
| Joseph Kruskal | MST 贪心 | 1956 论文 |
| Vasek Chvatal | 拟阵贪心 | 1979 拟阵理论论文 |
| Petr Mitrichev | 竞赛圈 DP 讲解 | Codeforces 博客 |
9.3.5 开发方法
| 方法 | 具体动作 | 何时用 |
|---|---|---|
| Greedy-first with counter-example | 先写贪心,立刻构造 3 个反例 | 任何疑似贪心题 |
| DP from recursion | 从暴力递归 → 加 memo → 自底向上 | 新 DP 题入门 |
| State-as-subproblem | 把状态显式定义为”已完成什么” | 设计 DP 状态 |
| Table-first DP | 先填 3×3 表,再写代码 | 序列 / 区间 DP |
| Roll-on-one-axis | 二维 → 一维时画箭头看依赖方向 | 空间优化 |
| Bitmask enumeration | for mask in range(1<<n) 调试 | 状压 DP |
9.4 经典问题与经典案例
| # | 问题 | 为什么重要 | 最简答案或图示 |
|---|---|---|---|
| 1 | 活动选择 / 区间调度 | 贪心入门 | 按结束时间排序,扫描 |
| 2 | LeetCode 435 无重叠区间 | 贪心典型 | 按右端点排序 + 计数 |
| 3 | LeetCode 55/45 跳跃游戏 | 贪心 + 反例构造 | 维护当前能到的最远下标 |
| 4 | Huffman 编码 | 优先队列贪心 | 每次合并最小的两个 |
| 5 | 0/1 背包 | DP 入门 | dp[i][w] = max(dp[i-1][w], dp[i-1][w-wi]+vi) |
| 6 | LeetCode 322 零钱兑换 | 完全背包 | 初始化 INF,dp[0]=0 |
| 7 | LeetCode 300 LIS | 一维 DP + 二分 | patience sorting O(n log n) |
| 8 | LeetCode 1143 LCS | 二维序列 DP | if a[i]==b[j]: dp[i+1][j+1]=dp[i][j]+1 else max(dp[i+1][j], dp[i][j+1]) |
| 9 | LeetCode 72 编辑距离 | 区间 DP 简化版 | dp[i+1][j+1] = min of 三种操作 + cost |
| 10 | LeetCode 312 戳气球 | 区间 DP | dp[l][r] = max over k of dp[l][k]+dp[k][r]+a[l]*a[k]*a[r] |
| 11 | LeetCode 464 我能赢吗 | 状压 DP 入门 | dfs(mask) 博弈 |
| 12 | LeetCode 847 访问所有节点的最短路径 | 状压 BFS | BFS 状态 = (node, mask) |
9.5 学习难点
概念难点
| 难点 | 为什么会卡 | 突破路径 |
|---|---|---|
| 状态定义 | 不知道该选哪几维 | 从暴力递归出发,找”做完第 i 步还剩什么” |
| 转移方程 | 状态之间的递推想不到 | 画转移图,每个状态标出前驱 |
| 初始化边界 | dp[0]、dp[i][0] 写错 | 用 n=1, n=2 手动填表反推 |
| 贪心证明 | 不会交换论证 | 先写出 DP 解,再用反例找漏洞 |
思维难点
| 难点 | 为什么会卡 | 突破路径 |
|---|---|---|
| 0/1 vs 完全背包遍历顺序 | 一不小心写成同序 | 画箭头:0/1 倒序、完全背包正序 |
| 滚动数组方向错 | 旧值被覆盖 | 把箭头画在二维表上,看依赖 |
| 区间 DP 边界 | dp[l][r] 的 l<=r 还是 l<r | 写 n=3 例子填表 |
| 状压状态数爆炸 | n=25 就跑不动 | 提前估算 n * 2^n,n>20 改 Meet-in-the-Middle |
工程难点
| 难点 | 为什么会卡 | 突破路径 |
|---|---|---|
| 空间超限 | 二维 dp 开 1e3×1e3 内存爆 | 压一维;用 array.array;用 numpy |
| 时间超限 | O(n²) 在 n=1e5 不行 | 找 O(n log n) 替代(LIS) |
| 整数溢出 | Python 自动 bigint,C++ 用 long long | Python 默认没事;C++ 用 long long |
| 输入规模 vs 答案 | 用错的 dp 数组维度 | 用 n=10 例子验一遍 |
9.6 技术标准与接口
9.6.1 Entity
| 名称 | 版本 / 文档 | 发布组织 | 状态 | 许可证 / 可访问性 |
|---|---|---|---|---|
| AtCoder Educational DP Contest | 26 题 | AtCoder | 永久开放 | 公开题面 + Editorial |
| LeetCode DP 题库 | 持续更新 | LeetCode | 订阅制 | ToS 管理 |
| CLRS 第 4 版 | 2022 | MIT Press | 主流教材 | 第三方 PDF 公开;纸质需购买 |
| CP-Algorithms DP 章节 | 持续更新 | 社区 | 活跃 | CC BY-SA |
9.6.2 Scope
- DP 适用:最优化、计数、存在性三类问题;状态空间可枚举。
- 贪心适用:区间调度、Huffman、活动选择、单调队列、跳跃游戏。
- 不适用:图最短路(用 BFS / Dijkstra);最大流(Ford-Fulkerson);NP-hard 无多项式解。
9.6.3 Structure
- DP 三要素:状态定义、转移方程、初始化(含 dp[0]、dp[边界])。
- 空间优化方向:滚动数组(去掉一维)、单调队列(优化转移)、位运算压缩状态。
- 必须掌握的方法:暴力递归 → 加 memo → 自底向上;画转移图;填 3×3 表验正确性。
9.6.4 Ecosystem
- 工具:
functools.lru_cache(memoization)、bisect(LIS 优化)、heapq(Huffman)、array.array(节省内存)。 - 在线评测:LeetCode、AtCoder、Codeforces、CSES。
- 训练集:AtCoder Educational DP Contest、USACO Guide DP 模块、CSES DP 章节。
9.6.5 Depth Tiers
| 层级 | 能力 | 贪心与 DP 的可观察标准 |
|---|---|---|
| L0 | 知道存在 | 知道贪心、DP 各自的适用条件 |
| L1 | 看得懂示例 | 能读懂别人的 DP 代码 |
| L2 | 能正确调用 | 能写 0/1 背包、LIS、LCS、编辑距离 |
| L3 | 能解释与排错 | 能设计新题型的状态与转移,能证明或推翻贪心 |
| L4 | 能设计与扩展 | 能把问题归约到已知范式或设计新范式 |
本子主题目标:L3。能独立设计状态转移 + 空间优化 + 给出贪心证明即达到。
9.6.6 Source
- AtCoder Educational DP Contest:26 题题面 + Editorial。
- CLRS 官网:第 4 版目录与勘误。
- CP-Algorithms DP:社区算法百科。
- 引用版本快照日期:2026-07-30。题号稳定,Editorial 持续更新。
10. 常见误区
- 贪心题不证明正确性,遇到反例就 WA;
- DP 状态多了一维或漏了一维,靠调试发现;
- 0/1 背包写错遍历顺序(该逆序写成了正序);
- 完全背包写错遍历顺序(该正序写成了逆序);
- 滚动数组时方向写反,旧值被覆盖;
- 区间 DP 把 l / r 的开闭写错(< vs <=);
- 状压 DP 没算状态数就开 2^25;
- 贪心选错排序键(如按起始时间排而不是结束时间);
- 初始化 dp 数组忘了设 INF 或 dp[0];
- 把”求方案数”和”求最优解”的 DP 模板混用;
- DP 写出来发现是”递归 + 备忘录”但复杂度仍是指数(没去重);
- 复杂度算错,把 O(n²) 当 O(n log n);
- 写完不复盘,下周遇到同类型还是不会。
11. 所有知识点分类
- 编程语言(辅):Python 列表 / 元组 / 字典、
functools.lru_cache自顶向下 memo、bisect做 LIS 优化、heapq做 Huffman / 优先队列、array.array节省内存。 - 数据结构与算法(主):贪心(交换论证 + 反例构造)、DP 三要素(状态 / 转移 / 初始化)、0/1 背包 / 完全背包 / 多重背包、序列 DP(LIS / LCS / 编辑距离 / 回文)、区间 DP(戳气球 / 矩阵链乘)、状压 DP(TSP / 优美排列)、空间优化(滚动数组 / 单调队列 / 位运算)。
- 计算机基础:递推与求和、最优性原理、拟阵理论(贪心适用条件)、P/NP 问题分类。
- 工程技术:复杂度推导(T(n))、画 3×3 状态转移表、箭头法判断滚动方向、
n × 2^n状态数估算、用 numpy /array.array控内存。 - Web 与后端:无直接关联。
- 前端与客户端:无直接关联。
- 数据与人工智能:无直接关联(DP 可用于序列标注 / 隐马尔可夫,但本计划不展开)。
- 项目与职业能力:AtCoder Educational DP Contest 26 题训练路径、LeetCode 中高级面试 DP 题(Medium 中占 1/3)、35 分钟独立设计状态转移、10 分钟构造贪心反例。
本计划归属:数据结构与算法 主 + 编程语言 辅。