登录以参加训练计划

这张思维导图展示了一套非常有条理的动态规划(Dynamic Programming, DP)学习路径,特别强调了从一维数组/字符串到图论的递进关系。
这种分类方式(如“左右找子结构”、“中间找子结构”等)是该特定课程(志宏说算法)的教学术语,本质上对应了算法竞赛中经典的DP模型(如线性DP、区间DP、背包问题、状压DP等)。
下面我按照图中的分类,为你整理了对应的 洛谷(Luogu) 经典题目,帮助你按图索骥进行训练。
第一部分:一维数组类 / 字符串类 (线性DP与背包)
这部分是DP的基础,主要解决“由前一个状态推导当前状态”的问题。
1. 左右找子结构 & 找1个子数组
核心逻辑: 通常只与 或前几个状态有关。对应经典的“最大子序和”模型。
- P1115 最大子段和(最经典的“找1个子数组”问题,必做)
- P1002 [NOIP2002 普及组] 过河卒(基础的网格路径计数,线性推导)
- P1216 [USACO1.5][IOI1994] 数字三角形 Number Triangles(经典的自上而下或自下而上推导)
2. 01背包问题 (属于“左右找子结构”的变种)
核心逻辑:选或不选,状态转移依赖于剩余容量。
- P1048 [NOIP2005 普及组] 采药(最标准的01背包模板题)
- P2871 [USACO07DEC] Charm Bracelet S(01背包标准题)
- P1060 [NOIP2006 普及组] 开心的金明(01背包变种)
- P1049 [NOIP2001 普及组] 装箱问题(求最小剩余空间,本质还是01背包)
3. 股票买卖问题
核心逻辑:状态机模型,每一天持有或不持有股票。 (注:洛谷上纯粹的股票题较少,这类题目在 LeetCode 上最全[121, 122, 123, 188等],但在洛谷可以用类似的线性状态机题目替代)
- P1420 最长连号(虽然简单,但体现了线性扫描的思维)
- P1969 [NOIP2011 提高组] 积木大赛(贪心/线性递推,思想类似)
- 建议去 LeetCode 刷:121. 买卖股票的最佳时机 等系列
4. 中间找子结构 (通常指 LIS 模型)
核心逻辑: 需要扫描 到 的所有状态来寻找最优解。最典型的是“最长上升子序列”。
- P1020 [NOIP1999 普及组] 导弹拦截(最长上升/不上升子序列,经典必做)
- P1091 [NOIP2004 提高组] 合唱队形(正向LIS + 反向LIS,经典拼接)
- P1439 【模板】最长公共子序列(虽然名字是LCS,但转化后其实是LIS的解法)
5. 两边找子结构 (区间 DP)
核心逻辑:大区间 的最优解依赖于小区间 、 或 。即区间动态规划。
- P1880 [NOI1995] 石子合并(区间DP祖师爷级别的题目,环形处理)
- P1063 [NOIP2006 提高组] 能量项链(环形区间DP)
- P3205 [HNOI2010] 合唱队(区间DP,考虑左右端点进队顺序)
- P4170 [CQOI2007] 涂色(经典的区间覆盖染色问题)
6. 两个数组 (LCS / 编辑距离)
核心逻辑: 表示数组A的前 个和数组B的前 个匹配的结果。
- P1439 【模板】最长公共子序列(前面提过,如果是 朴素做法就是这类,虽然该题数据要求更高)
- P2758 编辑距离(经典的两个字符串转换步数)
- P1140 相似基因(带权值的LCS变种)
7. 子集找子结构 (划分子集 / 子集和)
核心逻辑:通常涉及将集合划分为满足条件的子集,或者背包问题的变种。
- P1019 [NOIP2000 提高组] 单词接龙(虽然常搜做,但包含子结构拼接思想)
- P1164 小A点菜(01背包求方案数)
- P2392 kkksc03考前临时抱佛脚(搜索+剪枝,或者看作极小数据的子集划分DP)
第二部分:图类 (图论与DP的结合)
这部分对应图中的右侧分支,难度通常高于纯数组类DP。
1. 单源带条件最短路径 (分层图 / DP on Graph)
核心逻辑:在求最短路的基础上增加了“k次免费”、“油量限制”或“状态限制”。
- P4568 [JLOI2011] 飞行路线(分层图最短路,本质是状态机DP思想在图上的应用,k次免费机会)
- P1073 [NOIP2009 提高组] 最优贸易(在图上进行买卖,结合了SPFA/Dijkstra和DP思想)
- P3953 [NOIP2017 提高组] 逛公园(在图上进行DP计数,求k短路相关)
- P1462 通往奥格瑞玛的道路(二分答案 + 最短路 check)
2. 经过所有节点的路径 (状压 DP / TSP 问题)
核心逻辑:数据范围通常 ,需要用二进制位来表示“哪些节点走过,哪些没走过”。
- P1433 吃奶酪(经典的TSP旅行商问题,状压DP)
- P1171 售货员的难题(标准的TSP问题)
- P1896 [SCOI2005] 互不侵犯(状压DP入门,虽然不是路径,但是状态压缩思想一致)
- P2915 [USACO08NOV] Mixed Up Cows G(排列型状压DP)
学习建议
- 按顺序刷:先搞定“一维数组类”,尤其是最大子段和和01背包,这是所有DP的基石。
- 重模板:图中的分类其实就是模板。比如做“区间DP”时,脑子里要有
for len,for i,for k的三层循环结构。 - 看题解:如果卡住了,洛谷的题解区非常丰富,重点看那些解释了 “状态定义”(即 代表什么)和 “状态转移方程” 的题解。
祝你刷题愉快,早日攻克DP算法题!
这里面没有“树上的DP”吗?
你观察得非常仔细!这张思维导图中确实 没有明确列出“树形 DP”(Tree DP) 这一板块。
这张图主要聚焦在线性 DP(数组/字符串)和图论 DP(最短路/状压)上。然而,在算法竞赛(NOIP/CSP/ICPC)以及大厂面试中,树形 DP 是绝对的重点,甚至比复杂的图论 DP 考频更高。
为了补全你的学习拼图,我为你单独整理了树形 DP 的核心逻辑和洛谷经典题目:
补全板块:树形 DP (Tree DP)
核心逻辑: 树形 DP 的本质是在 树(或森林) 的数据结构上进行动态规划。 通常的套路是:DFS(深度优先搜索)。
- 自底向上:先递归处理子节点(子树),算出子节点的状态。
- 状态合并:将子节点的信息汇总给父节点,从而更新父节点的状态。
- 状态定义: 通常表示“以节点 为根的子树,处于 状态下的最优解”。
1. 入门模板:最大独立集 / 染色问题
核心逻辑:当前节点 选或不选,会限制子节点 的选择。
-
: 不选,子节点 可选可不选。
-
: 选,子节点 绝不能选。
-
P1352 没有上司的舞会(必做,树形DP的“Hello World”,核心是父子不能同时出现)
-
P1122 最大子树和(稍微变化,修剪枝叶,求权值最大的连通子块)
-
P2016 战略游戏(最小点覆盖,和舞会题逻辑互补)
2. 树上背包 (树形依赖背包)
核心逻辑:在树上做“01背包”或“分组背包”。 通常 表示以 为根的子树中,选了 个节点/体积的最大价值。因为要分配 给各个子树,通常需要两层循环(类似卷积),时间复杂度 或 。
- P2014 [CTSC1997] 选课(必做,树上背包的祖师爷,选了子节点必须选父节点)
- P2015 二叉苹果树(保留 根树枝,其实就是保留 个节点,标准树上背包)
- P1273 有线电视网(分组背包模型,求不亏本的最大用户数)
3. 树的直径与中心
核心逻辑:在树上找最长路径。 通常维护两个值:向下延伸的最长链和次长链。
- P1351 [NOIP2014 提高组] 联合权值(虽然可以用数学方法,但树形DP思维也可以解)
- P1099 [NOIP2007 提高组] 树网的核(求树的直径及其相关性质)
4. 换根 DP (二次扫描法)
核心逻辑:这是树形DP的进阶。 先假设 1 为根做一次 DFS(自底向上),算出所有节点的子树贡献; 再做第二次 DFS(自顶向下),算出“父亲方向”对当前节点的贡献,从而求出以任意节点为根时的答案。
- P3478 [POI2008] STA-Station(必做,换根DP模板题,求以谁为根深度和最大)
- P2986 [USACO10MAR] Great Cow Gathering G(带权值的换根DP)
- P1364 医院设置(数据范围小可用 Floyd,数据大则必须用换根 DP)
总结建议
如果你按照那张图学习,在学完 “一维数组类” 和 “子集找子结构” 之后,建议立刻插入“树形 DP”的学习,然后再去学右边的“图类”。
因为树形 DP 实际上是“子集找子结构”在树这种特殊图上的应用,难度介于线性 DP 和 状压 DP 之间,是承上启下的关键环节。
树上DP有哪些洛谷入门题?
你好!很高兴看到你开始攻克树形DP。这是动态规划与图论结合的第一步,也是联赛(NOIP/CSP-S)中非常高频的考点。
树形DP的核心思想其实只有一句话:父亲的状态由子节点的状态转移而来(自底向上)。 代码实现上,通常使用 DFS(后序遍历)。
我为你精选了洛谷上最适合入门的几道题目,并按题型模式进行了分类。请按顺序练习。
第一阶段:经典的“选与不选”模型
这是树形DP最基础的模型,状态通常定义为 (不选 )和 (选 )。
1. P1352 [USACO05NOV] 没有上司的舞会
- 难度:🟡 普及/提高-
- 一句话题意:给一棵树,每个点有快乐值。选了某个点,就不能选它的直接父节点。求最大快乐值。
- 教练点评:这是树形DP的“Hello World”,绝对的板子题。
- 核心方程:
- 选 :子节点 必定不能选
- 不选 :子节点 可选可不选(取最大)
2. P2016 战略游戏
- 难度:🟡 普及/提高-
- 一句话题意:给一棵树,在节点上放士兵,一个士兵可以看守与该节点相连的所有边。求最少放多少士兵能看守所有边。
- 教练点评:这是最小点覆盖问题。跟上一题是对偶关系。
- 思路提示:
- 选 :子节点 选不选都可以,取花费少的。
- 不选 :为了看守 这条边,子节点 必须选。
3. P1122 最大子树和
- 难度:🟡 普及/提高-
- 一句话题意:树上每个点有权值(可能为负),求一个连通子树,使得点权之和最大。
- 教练点评:这题不需要二维数组。思路非常贪心——如果子树贡献是正的就要,负的就扔掉。
第二阶段:树上背包(泛化物品背包)
这种题目通常限制选 个节点/边,或者有体积限制。其实就是把背包问题搬到了树上:把子树看作是物品组。
4. P2015 二叉苹果树
- 难度:🟢 普及+/提高
- 一句话题意:保留树上 根树枝,使得留下的苹果最多。
- 教练点评:树上背包的入门题。因为是二叉树,所以转移方程比较好写(枚举给左儿子分多少根树枝,右儿子分多少)。
- 状态定义: 表示以 为根的子树中,保留 条边能得到的最大值。
5. P2014 [CTSC1997] 选课
- 难度:🟢 普及+/提高
- 一句话题意:选课有先修关系(形成森林),每门课有学分。限制选 门课,求最大通常。
- 教练点评:树上背包的必修课。
- 技巧:
- 题目给的是森林(多棵树),需要建立一个虚拟根节点 0 把它们连成一棵大树。
- 这是多叉树,需要用类似“分组背包”的思路:枚举给当前子节点 分配多少体积 。
- 时间复杂度是 或优化后的 。
第三阶段:树的直径与中心(路径相关)
这类题目关注树上最长的路径或特定的节点性质。
6. P1351 [NOIP2014 提高组] 联合权值
- 难度:🟢 普及+/提高
- 一句话题意:求树上距离为 2 的所有点对的权值乘积之和及最大值。
- 教练点评:这题其实可以用简单的遍历解决,但它蕴含了树形DP处理子树信息的思想(维护最大值和次大值)。
7. P1099 [NOIP2007 提高组] 树网的核
- 难度:🔵 提高+/省选-
- 一句话题意:涉及树的直径和偏心距。
- 教练点评:虽然难度标得高,但核心是求树的直径。先学会怎么用两次 DFS 或 树形 DP 求直径,这题是进阶训练。
8. P1272 重建道路
- 难度:🟢 普及+/提高
- 一句话题意:切断最少的边,得到一个节点数为 的子树。
- 教练点评:这是一道计数类的树形DP。思考方向: 表示以 为根,保留 个节点的最小删边数。
教练的刷题建议
- 先做 P1352,如果你能独立写出这题,就理解了树形DP的 50%。
- 再做 P2014,这是树上背包的通解模板,学会了这个,P2015 就迎刃而解了。
- 注意边界:树形DP容易在叶子节点或根节点处写错边界,要在草稿纸上模拟一下叶子节点的返回值。
- 建图:记得用邻接表(
vector<int> G[N]或 链式前向星)存图,题目通常是无向边,DP时要传入father参数防止死循环。
解释前面说的LIS 模型
LIS (Longest Increasing Subsequence),即最长上升子序列。
在之前的思维导图中,它被归类为“中间找子结构”。这是一个非常形象的描述,因为它揭示了 LIS 模型与基础 DP(如最大子段和)的核心区别。
下面我为你拆解这个模型的核心逻辑、为什么叫“中间找”,以及它的代码模板。
1. 什么是“子序列”?
首先要区分两个概念,这是新手的易错点:
- 子数组/子串 (Subarray/Substring):必须是连续的。
- 例子:
[10, 9, 2, 5]的子数组是[9, 2]。
- 例子:
- 子序列 (Subsequence):可以是不连续的,但相对顺序不能变。
- 例子:
[10, 9, 2, 5, 3, 7, 101, 18] - 它的一个上升子序列是:
[2, 5, 7, 101]。 - 另一个上升子序列是:
[2, 3, 7, 18]。
- 例子:
LIS 问题就是: 在一个给定的数组中,找到一个最长的子序列,使得这个子序列中的元素是严格递增的。
2. 为什么叫“中间找子结构”?
回顾一下 “左右找子结构”(比如最大子段和):
- 计算 时,我们通常只需要看 (它左边的紧邻邻居)。
而在 LIS 模型中:
- 为了计算以第 个数字结尾的最长子序列长度 ,仅仅看 是不够的。
- 你需要回头扫描 到 之间的所有位置 。
- 只要 ,说明 可以接在 后面。
- 我们要从这些能接的位置里,挑一个本来就最长的。
因为这种 “回头看所有前面状态” 的特性,所以被称为“中间找子结构”或“扫描式 DP”。
为了回看“所有前面的状态”,就需要 使用二维数组把状态记忆化 以及 从简单的初始边界条件开始递推 !
3. 核心逻辑与状态转移方程 ()
状态定义
表示:必须以 nums[i] 这个数结尾的最长上升子序列的长度。
(注意:一定是包含 nums[i] 的)
状态转移方程
对于每一个 ,我们需要遍历 ():
$$dp[i] = \max(dp[j]) + 1, \quad \text{其中 } nums[j] < nums[i] $$- 如果找不到任何比 小的 ,则 (只有它自己)。
最终答案
答案不是 ,而是整个 数组中的最大值:。
4. 代码模板 (C++)
这是最基础的 写法,也是理解 DP 思想的最佳模板。
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
int main() {
int n;
cin >> n;
vector<int> nums(n);
for(int i = 0; i < n; i++) cin >> nums[i];
// dp[i] 初始化为 1,因为每个元素本身至少长度为 1
vector<int> dp(n, 1);
int ans = 1; // 记录全局最大值
for (int i = 1; i < n; i++) { // 枚举当前结尾的元素
for (int j = 0; j < i; j++) { // “中间找”:回头扫描前面的元素
if (nums[j] < nums[i]) { // 如果能接上
dp[i] = max(dp[i], dp[j] + 1);
}
}
ans = max(ans, dp[i]); // 更新全局最大值
}
cout << ans << endl;
return 0;
}
5. 进阶: 贪心 + 二分法
在实际面试或竞赛中,如果数据范围 ,上面的 会超时。LIS 有一个经典的优化解法,虽不属于纯 DP,但非常重要。
核心思想(贪心):
- 如果我们要让上升子序列尽可能长,那么序列中的数字应该尽可能小,这样后面才容易接上更大的数。
- 我们维护一个数组
tails,其中tails[k]存储长度为 k+1 的上升子序列的最小结尾元素。 - 遍历
nums时,通过二分查找更新tails数组。
(这也是洛谷 P1020 导弹拦截 必须掌握的解法)
6. LIS 模型的经典变种
理解了 LIS,你就能解决一系列变种题:
- 最长不下降子序列:
- 条件变成 。
- 合唱队形 (洛谷 P1091):
- 先上升后下降。
- 解法:求一遍正向 LIS (),再求一遍反向 LIS (),答案就是 。
- 俄罗斯套娃信封 (LeetCode 354):
- 二维的 LIS。
- 解法:先按宽度排序,如果宽度相同按高度降序,然后对高度求 LIS。
- 最少拦截系统 (Dilworth 定理):
- 洛谷 P1020 的第二问。
- 定理:一个序列的最少下降子序列划分数 = 该序列的最长上升子序列长度。
总结: LIS 模型是 DP 入门到进阶的必修课,它教会了我们 “状态不仅仅可以只看前一个,还可以回头看前面所有” 这一重要思维。
动态规划循序渐进洛谷题单2
作为OI金牌教练,我为你精心设计了这份动态规划题单,涵盖从入门到进阶的全部核心知识点。每个阶段都有明确的学习目标和精选题目,帮助你系统掌握DP思想。
🏆 学习建议
- 每个阶段至少完成80%的题目再进入下一阶段
- 先独立思考,再参考题解
- 总结每道题的状态定义和转移方程
- 定期回顾已做题目,加深理解
📚 第一阶段:线性DP(基础)
学习目标:掌握DP的基本思想,理解状态定义和转移方程
核心概念:状态、转移方程、边界条件、最优子结构
| 题目编号 | 题目名称 | 难度 | 知识点 |
|---|---|---|---|
| P1216 | 数字三角形 | 普及- | DP入门、递推 |
| P1002 | 过河卒 | 普及/提高- | 路径计数、无障碍DP |
| P1044 | 栈 | Catalan数、状态转移 | |
| P1025 | 数的划分 | 整数划分、状态设计 | |
| P1077 | 摆花 | 限制条件的计数DP | |
| P1115 | 最大子段和 | 普及- | 经典线性DP、状态优化 |
| P1280 | 尼克的任务 | 普及/提高- | 逆向思维DP |
| P1466 | 集合 Subset Sums | 01背包思想的应用 |
🎒 第二阶段:背包问题(重点)
学习目标:掌握各类背包问题的建模和优化方法
核心概念:01背包、完全背包、多重背包、分组背包
| 题目编号 | 题目名称 | 难度 | 知识点 |
|---|---|---|---|
| P1048 | 采药 | 普及- | 01背包模板 |
| P1616 | 疯狂的采药 | 普及/提高- | 完全背包模板 |
| P1060 | 开心的金明 | 01背包变形、价值最大化 | |
| P1064 | 金明的预算方案 | 提高/省选- | 分组背包、依赖背包 |
| P1833 | 樱花 | 多重背包优化 | |
| P1776 | 宝物筛选 | 二进制优化 | |
| P3188 | [HNOI2007]梦幻岛宝珠 | 省选/NOI- | 分组背包、状态压缩 |
| P2925 | [USACO08DEC]Patting Heads S | 普及+/提高 | 完全背包思想的计数应用 |
📊 第三阶段:区间DP
学习目标:掌握区间上的动态规划问题
核心概念:区间状态定义、合并转移、区间枚举顺序
| 题目编号 | 题目名称 | 难度 | 知识点 |
|---|---|---|---|
| P1435 | 回文字串 | 普及+/提高 | 最长回文子序列 |
| P1220 | 关路灯 | 提高+/省选- | 区间DP、状态记录位置 |
| P1880 | 石子合并 | 提高/省选- | 经典区间DP、环形处理 |
| P4170 | 涂色 | 提高+/省选- | 区间DP、状态合并 |
| P2470 | 压缩 | 省选/NOI- | 区间DP、状态设计 |
| P3205 | 合唱队 | 提高+/省选- | 区间DP、方向状态 |
| P4302 | 道路相遇 | 省选/NOI- | 区间DP、LCA |
🌳 第四阶段:树形DP
学习目标:掌握在树上进行动态规划的方法
核心概念:子树状态、根节点转移、树的遍历顺序
| 题目编号 | 题目名称 | 难度 | 知识点 |
|---|---|---|---|
| P1352 | 没有上司的舞会 | 普及+/提高 | 树形DP入门、选/不选 |
| P1122 | 最大子树和 | 树形DP、子树贡献 | |
| P2015 | 二叉苹果树 | 提高/省选- | 树形背包 |
| P1273 | 有线电视网 | 提高+/省选- | 树形DP、分组背包 |
| P2458 | 保安站岗 | 树形DP、三种状态 | |
| P3174 | [HAOI2009]毛毛虫 | 树形DP、最长链 | |
| P4211 | 树上的数 | 省选/NOI- | 树形DP、状态设计 |
🎯 第五阶段:状态压缩DP
学习目标:掌握用二进制表示状态的动态规划方法
核心概念:状态压缩、位运算、状态转移优化
| 题目编号 | 题目名称 | 难度 | 知识点 |
|---|---|---|---|
| P1433 | 吃奶酪 | 普及+/提高 | 状态压缩DP入门 |
| P1896 | 互不侵犯 | 提高/省选- | 状压DP、行转移 |
| P2704 | 炮兵阵地 | 提高+/省选- | 状压DP、状态压缩优化 |
| P3694 | 邦邦的大合唱站队 | 状压DP、费用提前计算 | |
| P3195 | 玩具装箱 | 提高/省选- | 单调队列优化DP |
| P4163 | [SCOI2007]排列 | 省选/NOI- | 状压DP、数位限制 |
| P4640 | [IOI2014]wall砖墙 | 状压DP、滚动数组 |
🔢 第六阶段:数位DP
学习目标:掌握处理数字计数问题的动态规划方法
核心概念:数位分解、状态记录、记忆化搜索
| 题目编号 | 题目名称 | 难度 | 知识点 |
|---|---|---|---|
| P2602 | 数字计数 | 提高/省选- | 数位DP入门 |
| P3413 | SAC#1 - 萌数 | 数位DP、回文判断 | |
| P4127 | 同类分布 | 提高+/省选- | 数位DP、模运算 |
| P4999 | 烦人的数学作业 | 提高/省选- | 数位DP、数字和 |
| P3281 | [SCOI2013]数数 | 省选/NOI- | 数位DP、高精度 |
| P5104 | 红包发红包 | 数位DP、期望 |
⭐ 第七阶段:高级DP技巧
学习目标:掌握复杂问题的DP建模和优化方法
核心概念:优化技巧、多维DP、状态设计
| 题目编号 | 题目名称 | 难度 | 知识点 |
|---|---|---|---|
| P2051 | 中国象棋 | 提高+/省选- | 状态压缩、二维DP |
| P2150 | 寿司晚宴 | 省选/NOI- | 状压DP、博弈论 |
| P3206 | [HNOI2010]城市建设 | 动态树分治、DP | |
| P4363 | [九省联考2018]一双木棋 | 状压DP、博弈论 | |
| P5020 | 货币系统 | 提高+/省选- | 完全背包、数学优化 |
| P5325 | [BJOI2019]删数 | 省选/NOI- | 区间DP、栈优化 |
📈 进阶挑战:NOI/IOI真题
完成前七个阶段后,可以挑战这些更高难度的题目:
| 题目编号 | 题目名称 | 难度 |
|---|---|---|
| P4052 | 环形珍珠 | NOI/IOI- |
| P4290 | 玩具装箱 | |
| P5023 | 树屋阶梯 | |
| P5158 | [USACO18DEC]Convention II | |
| P5298 | [PKUWC2018]Minimax |
💡 教练寄语
- 动态规划的核心是状态定义和转移方程,这需要大量练习来培养直觉
- 遇到难题时,先尝试简化问题,再逐步增加复杂度
- 学会从问题中抽象出DP模型,这是DP学习的关键
- 定期总结不同类型DP的共性和特点,形成自己的知识体系
祝你在动态规划的学习道路上越走越远!🏆
- 参加人数
- 1
- 创建人