下面是一个从入门到精通「背包问题」的完整学习路线,分阶段梳理常见题型、核心思路和推荐练习。
一、基础篇:经典 0-1 背包
目标:掌握最基本的状态定义、转移方程和滚动数组优化。
-
题型
-
01背包(每件物品最多取 1 件)
-
状态1:
dp[i][j]= 前 i 件物品,容量为 j 时最大价值 -
状态2:
dp[j]= 容量为 j 时最大价值(滚动数组) -
转移1:
dp[i][j] = max(dp[i-1][j], dp[i-1][j-w[i]]+v[i]) -
转移2:
for j=V..w[i]: dp[j] = max(dp[j], dp[j-w[i]] + v[i]) -
优化:一维滚动数组
for j=V..w[i]
-
-
核心刷题
二、进阶篇:完全背包 & 多重背包
目标:理解物品可重复与数量限制时的区别,掌握单维最优遍历和二进制拆分法。
-
完全背包(Unbounded)
- 转移:
for j=w[i]..V: dp[j]=max(dp[j],dp[j-w[i]]+v[i])
- 转移:
-
多重背包(Bounded)
-
方法一:二进制拆分 → 转化为若干 01 背包
-
方法二:单调队列优化(更高阶)
-
-
经典练习
-
Luogu P1064《分组背包》
-
AtCoder dp “Knapsack 2”
-
CF 1203F “Almost All Divisors”
-
三、组合篇:分组背包 & 二维背包
目标:掌握分组内选 0/1、二维资源约束。
-
分组背包(Group Knapsack)
-
每组内选 0–1 件,组间互斥
-
转移:
for each group; for j=V..0; for each item in group: dp[j]=max(dp[j],dp[j-w]+v)
-
-
二维/多维背包
- 额外资源(如体积+重量双约束):
dp[j][k]
- 额外资源(如体积+重量双约束):
-
练习
-
Luogu P1553《方格取数》
-
CF 768E “Game of Stones”
-
四、依赖篇:树形 & 图上背包
目标:会处理物品依赖关系、树上 DP。
-
树形背包
- 树形结构的多重背包,使用 DFS+背包合并
-
有向无环图(DAG)背包
- 按拓扑序合并状态
-
练习
-
Luogu P1114《树上背包》
-
HDU 1225《食物链毒奶问题》(简化版)
-
五、优化篇:状态压缩 & 单调队列
目标:通过位运算、双端队列等提高效率。
-
状态压缩(Bitset)
- C++
bitset加速 01 背包:bs |= (bs<<w[i]);
- C++
-
单调队列优化多重/完全背包
- 滑动窗口极值维护,时间降至 O(NV)
-
练习
-
CF 660F “Bear and Bowling 4”
-
Luogu P2827《单调队列优化多重背包》
-
六、拓展篇:高级技巧与变种
-
分治+矩阵乘法(大容量、多组问答)
-
Meet-in-the-Middle(N≈40,分组枚举)
-
概率/期望背包(DP 求方案数或概率)
-
背包计数 & 取模(方案数、最小费用流结合)
-
练习
-
CF 1553G “Common Divisors”
-
SPOJ MTRIAREA(方案数)
-
七、刷题建议与资源
-
系统学习:
-
《算法竞赛入门经典》背包章节
-
CP-Algorithms 上的Knapsack DP 教程
-
-
题库练习:
-
Luogu 背包专题
-
Codeforces “Edu” DP 模块
-
AtCoder dp 系列
-
-
阶段性总结:
-
每攻克一种题型,记录状态定义、递推方式、优化思路
-
建议制作一份个人笔记或思维导图,整理所有公式与套路
-
温馨提示:
- 每个阶段至少刷通 10–15 道典型题,遇到瓶颈要及时回顾讲解视频或专题文章。
- 在 Codeforces/AtCoder 上参与带有“knapsack”标签的比赛,提高实战经验。
- 结合实际比赛,多练「时间复杂度可接受的最优解」与「代码简洁度」。
祝你早日通关背包专题,ACM 比赛一路斩获高分!
