CalcGuide · 技术博客主页 / 一页纸学习计划
🔥极高

贪心与动态规划:从区间调度到状态转移方程

分类:数据结构与算法 · 路径:docs/topics/greedy-and-dp/README.md

#algorithms#greedy#dp#memoization#optimization

能用贪心证明 / 反证,能写出 DP 状态、转移、初始化、空间优化

父主题

算法设计方法:从递归到动态规划

子主题(0)

贪心与动态规划:从区间调度到状态转移方程

0. 元信息

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. 序列 DP2 天2.5 天1143 LCS / 72 编辑距离 / 5 / 516
5. 区间 DP1.5 天2 天312 戳气球 / 1039 三角剖分
6. 状压 DP1.5 天2 天464 / 526 / 847 / 1434
7. 空间优化与综合刷题1.5 天2.5 天滚动数组 + AtCoder DP Contest

每天 1.5~2 小时。3 周方案聚焦前 5 阶段;4 周方案多一周做综合刷题与空间优化。

3. 九阶段表(精简)

3.1 核心知识

3.2 实践产出

3.3 可观察学会标准

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.pypytest week1/day2/test_greedy.py 5 passed;LeetCode 5/5 AC;每题记录排序键与正确性一句话证明
Day 3DP 入门 5 道:70 爬楼梯、198 打家劫舍、64 最小路径和、322 零钱兑换、300 LISweek1/day3/dp_intro.pypytest week1/day3/test_dp.py 5 passed;LeetCode 5/5 AC;为 300 LIS 写 O(n log n) patience sorting 优化
Day 40/1 背包 + 完全背包 4 道:416 分割等和子集、494 目标和、518 零钱兑换 II、474 一和零week1/day4/knapsack.pypytest 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.pypytest 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.pypytest 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 分钟)

  1. 写暴力递归 lps(s, i, j)
  2. 加 memo → 自顶向下 DP;
  3. 改自底向上二维 DP dp[i][j]
  4. 压一维滚动数组;
  5. 对比四版耗时。

步骤 B —— 4 类边界用例(30~45 分钟)

#用例期望行为验证命令
B1空串 ""返回 0pytest -k test_empty
B2单字符 "a"返回 1pytest -k test_single
B3全相同 "aaaa"返回 4pytest -k test_all_same
B4全相反 "abcd"返回 1pytest -k test_all_distinct

Day 7 当天必完成步骤 A;步骤 B 至少完成 B1、B3。

5. 阶段通用验收(精简)

  1. 不看答案重写 25 道 DP 模板;
  2. 用自己的话解释贪心和 DP 的适用边界;
  3. 画出每道 DP 题的状态转移表(二维表填 3×3);
  4. 测试空数据、单元素、相同元素、相反元素四档;
  5. 至少准备 3 组自定义数据贴出实际输出;
  6. 记录每题时间空间复杂度,并指出哪一维能压缩;
  7. 能给现有 DP 加维度(如加一维费用)或压维度(如二维 → 一维)。

6. 最终验收

7. 综合项目

首选:算法可视化桌面工具(必做:CLI 输入 + 输出 + 可选 GUI)。
备选:自动评测器(从 LeetCode / AtCoder 拉指定题目的测试用例,本地批量跑、对比时间、生成错题本)。
备选:算法题模板生成器(给定题型关键词 → 输出 Python 模板:状态定义 / 转移 / 初始化 / 空间优化)。

算法可视化工具必做要求:

任何综合项目都必须包含:

  1. 需求说明(含输入输出约定);
  2. 数据结构与算法选择理由(为何用 DP、为何选这种状态);
  3. 核心模块说明(Solver / Recorder / Renderer 三层);
  4. 模块化源码(每题单独文件 + 公共 base class);
  5. 边界测试(n=0, 1, 2, 8, 10 + 空数据 + 极端数据);
  6. 运行说明(Makefile 或清晰的 python -m 命令);
  7. README(项目介绍、运行步骤、目录结构、复盘);
  8. 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.md4 类边界用例的输入 / 期望 / 实际

本主题贡献

3 职责

  1. 给出可证明的贪心策略 —— 区间调度按”结束时间”排序(活动选择)、跳跃游戏维护”最远可达下标”、Huffman 用优先队列每次合并最小两个;并能用交换论证(找等价代换的”反序对”)或拟阵(独立集 + 交换性质)证明正确性,不能证则必须退到 DP。
  2. 把 DP 拆成三要素 —— 状态定义(“做完第 i 步还剩什么”)、转移方程(前驱状态 + 当前一步的递推)、初始化(含 dp[0]dp[i][0] 边界);并在二维 → 一维滚动数组时画箭头验”旧值不被新值覆盖”。
  3. 用状态压缩处理维度爆炸 —— 0/1 背包 vs 完全背包的遍历方向(0/1 逆序、完全背包正序)、LIS 用 patience sorting 压到 O(n log n) 单调栈、TSP 状压用 dp[mask][i] 估算 n × 2^n 状态数。

4 交付物

  1. 33 道题解(25 DP + 8 贪心)+ 4 类边界用例日志(空 / 单元素 / 全相同 / 全相反)。
  2. 算法可视化工具(CLI → DP 填表过程 + 贪心 vs DP 反例对比 + 状态转移表二维填表截图)。
  3. 至少 5 道 DP 题的二维状态转移表(70 爬楼梯 / 198 打家劫舍 / 322 零钱兑换 / 1143 LCS / 72 编辑距离)落 notes/state-tables/ + 至少 3 道疑似贪心题的反例构造(含输入 → 反例 → 错误输出)落 notes/greedy-counters/
  4. DP 模板 5 件套(0/1 背包 / 序列 DP / 区间 DP / 状压 DP / 滚动数组)落 notes/dp-templates/,每个模板标明”遍历方向”与”压缩维度”。

3 指标

  1. 35 分钟内独立设计 0/1 背包 / LIS / LCS / 矩阵链乘的状态与转移(覆盖背包、序列、区间、状压四大 DP 范式)。
  2. 10 分钟内构造 435 / 55 / 134 等疑似贪心题的反例(证明”贪心不是万能”已固化为本能 —— 任何贪心策略先问一句”什么时候会反例”)。
  3. 二维 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~4Ahttps://www-cs-faculty.stanford.edu/~knuth/taocp.html拿来当字典,遇到细节再查
1~6刷题平台LeetCodehttps://leetcode.cn/中文题库;DP / 贪心按 tag 刷
1~6刷题平台Codeforceshttps://codeforces.com/模拟赛 + Editorial
1~3DP 训练AtCoder Educational DP Contesthttps://atcoder.jp/contests/dp26 题系统性 DP 训练;必跑
1~6EditorialAtCoder Editorialhttps://atcoder.jp/ABC/ARC/AGC 公开题解
1~5范式Kleinberg & Tardos《Algorithm Design》https://www.cs.princeton.edu/~smattw/范式 + 网络流 + NP 完全;与 CLRS 互补
3训练营Petrozavodsk Camphttps://codeforces.com/groups/c3v4QqHRIy高强度团队训练;难题偏多
1~5框架labuladong DP 框架https://labuladong.online/algo/中文框架化讲解;先自己写再对照
1~5图解CP-Algorithms DP 章节https://cp-algorithms.com/英文图解 + 代码;当字典
1~6训练USACO Guidehttps://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~4Ahttps://www-cs-faculty.stanford.edu/~knuth/taocp.html拿来当字典,遇到细节再查
1~6刷题平台LeetCodehttps://leetcode.cn/中文题库;DP / 贪心按 tag 刷
1~6刷题平台Codeforceshttps://codeforces.com/模拟赛 + Editorial
1~3DP 训练AtCoder Educational DP Contesthttps://atcoder.jp/contests/dp26 题系统性 DP 训练;必跑
1~6EditorialAtCoder Editorialhttps://atcoder.jp/ABC/ARC/AGC 公开题解
1~5范式Kleinberg & Tardos《Algorithm Design》https://www.cs.princeton.edu/~smattw/范式 + 网络流 + NP 完全;与 CLRS 互补
3训练营Petrozavodsk Camphttps://codeforces.com/groups/c3v4QqHRIy高强度团队训练;难题偏多
1~5框架labuladong DP 框架https://labuladong.online/algo/中文框架化讲解;先自己写再对照
1~5图解CP-Algorithms DP 章节https://cp-algorithms.com/英文图解 + 代码;当字典
1~6训练USACO Guidehttps://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.115.4、16.116.3
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 Editorial26 题官方题解系统训练用
labuladong DP 框架中文框架当 Cheatsheet
CP-Algorithms DP 章节英文图解 + 代码当字典
USACO Guide DP 模块按难度递进长期刷题路线

9.3.4 核心人物

人物主要影响建议追踪的材料
Richard BellmanDP 命名 + 最优性原理1954 RAND 报告
David HuffmanHuffman 编码1952 论文
Joseph KruskalMST 贪心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 enumerationfor mask in range(1<<n) 调试状压 DP

9.4 经典问题与经典案例

#问题为什么重要最简答案或图示
1活动选择 / 区间调度贪心入门按结束时间排序,扫描
2LeetCode 435 无重叠区间贪心典型按右端点排序 + 计数
3LeetCode 55/45 跳跃游戏贪心 + 反例构造维护当前能到的最远下标
4Huffman 编码优先队列贪心每次合并最小的两个
50/1 背包DP 入门dp[i][w] = max(dp[i-1][w], dp[i-1][w-wi]+vi)
6LeetCode 322 零钱兑换完全背包初始化 INF,dp[0]=0
7LeetCode 300 LIS一维 DP + 二分patience sorting O(n log n)
8LeetCode 1143 LCS二维序列 DPif a[i]==b[j]: dp[i+1][j+1]=dp[i][j]+1 else max(dp[i+1][j], dp[i][j+1])
9LeetCode 72 编辑距离区间 DP 简化版dp[i+1][j+1] = min of 三种操作 + cost
10LeetCode 312 戳气球区间 DPdp[l][r] = max over k of dp[l][k]+dp[k][r]+a[l]*a[k]*a[r]
11LeetCode 464 我能赢吗状压 DP 入门dfs(mask) 博弈
12LeetCode 847 访问所有节点的最短路径状压 BFSBFS 状态 = (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 longPython 默认没事;C++ 用 long long
输入规模 vs 答案用错的 dp 数组维度用 n=10 例子验一遍

9.6 技术标准与接口

9.6.1 Entity

名称版本 / 文档发布组织状态许可证 / 可访问性
AtCoder Educational DP Contest26 题AtCoder永久开放公开题面 + Editorial
LeetCode DP 题库持续更新LeetCode订阅制ToS 管理
CLRS 第 4 版2022MIT Press主流教材第三方 PDF 公开;纸质需购买
CP-Algorithms DP 章节持续更新社区活跃CC BY-SA

9.6.2 Scope

9.6.3 Structure

9.6.4 Ecosystem

9.6.5 Depth Tiers

层级能力贪心与 DP 的可观察标准
L0知道存在知道贪心、DP 各自的适用条件
L1看得懂示例能读懂别人的 DP 代码
L2能正确调用能写 0/1 背包、LIS、LCS、编辑距离
L3能解释与排错能设计新题型的状态与转移,能证明或推翻贪心
L4能设计与扩展能把问题归约到已知范式或设计新范式

本子主题目标:L3。能独立设计状态转移 + 空间优化 + 给出贪心证明即达到。

9.6.6 Source

10. 常见误区


11. 所有知识点分类

  1. 编程语言(辅):Python 列表 / 元组 / 字典、functools.lru_cache 自顶向下 memo、bisect 做 LIS 优化、heapq 做 Huffman / 优先队列、array.array 节省内存。
  2. 数据结构与算法(主):贪心(交换论证 + 反例构造)、DP 三要素(状态 / 转移 / 初始化)、0/1 背包 / 完全背包 / 多重背包、序列 DP(LIS / LCS / 编辑距离 / 回文)、区间 DP(戳气球 / 矩阵链乘)、状压 DP(TSP / 优美排列)、空间优化(滚动数组 / 单调队列 / 位运算)。
  3. 计算机基础:递推与求和、最优性原理、拟阵理论(贪心适用条件)、P/NP 问题分类。
  4. 工程技术:复杂度推导(T(n))、画 3×3 状态转移表、箭头法判断滚动方向、n × 2^n 状态数估算、用 numpy / array.array 控内存。
  5. Web 与后端:无直接关联。
  6. 前端与客户端:无直接关联。
  7. 数据与人工智能:无直接关联(DP 可用于序列标注 / 隐马尔可夫,但本计划不展开)。
  8. 项目与职业能力:AtCoder Educational DP Contest 26 题训练路径、LeetCode 中高级面试 DP 题(Medium 中占 1/3)、35 分钟独立设计状态转移、10 分钟构造贪心反例。

本计划归属:数据结构与算法 主 + 编程语言 辅。


直接依赖(1)

查看知识图谱 · 热度 🔥极高