背包问题总结
一、什么是背包问题?
定义:给定一个容量为 W 的背包和 n 件物品,每件物品有一个重量 w[i] 和价值 v[i],要求选择若干物品放入背包,在不超过容量的前提下,使总价值最大。
背包问题本质是:约束优化 + 组合选择。
二、什么时候考虑用“背包思想”?
你可以在如下类型的问题中尝试用背包建模:
| 题目特征 | 关键词 | 是否适合背包建模? |
|---|---|---|
| 有一个资源上限(如时间、钱、容量) | “最多”、“不超过”、“限制在…” | 资源即背包容量 |
| 有多个选项可选,每个选项有代价和收益 | “每个选择有花费和收益”、“从中选择一些” | 每个选项就是一个“物品” |
| 要最大化或最小化一个目标值(如最大收益、最小时间) | “求最大值/最小值”、“最优” | 属于优化问题 |
| 每个选项只能选一次/多次/无限次 | “可重复选”/“不可重复” | 可映射到 0-1、完全、多重背包 |
| 组合问题,多个变量之间的选择组合 | “在多个物品中挑选” | 用状态转移建模组合方式 |
一句话记忆:
多个物品(选项),有一个资源限制,要做出最优组合决策,就可以考虑“背包思想”。
三、常见背包模型(及其差异)
| 类型 | 是否可重复 | 限制条件 | 应用举例 |
|---|---|---|---|
| 0-1 背包 | 否 | 每个物品最多选一次 | 挑战任务只能做一次 |
| 完全背包 | 是(无限) | 每个物品可选任意次 | 硬币兑换、无限库存商品 |
| 多重背包 | 是(有限) | 每个物品最多选 k 次 | 有限库存下的选购问题 |
| 分组背包 | 分组内最多选一个 | 每组内只能选一个 | 每种类别选一个代表 |
| 混合背包 | 混合限制 | 混合以上任意模型 | 综合现实场景,如同时有限和无限物品 |
| 二维/多维背包 | 多维限制 | 除重量外还有其他限制 | 同时限制时间/金钱等多种资源 |
四、状态表示 & 转移方程
通用思路
-
状态定义:
dp[i][j]表示前i个物品中,容量为j时可获得的最大价值。 -
状态转移:
- 不选第 i 个物品:
dp[i][j] = dp[i-1][j] - 选第 i 个物品:
dp[i][j] = dp[i-1][j - w[i]] + v[i](要满足j >= w[i])
- 不选第 i 个物品:
状态压缩(降维优化)
因为 dp[i][*] 只依赖于 dp[i-1][*],所以可以使用一维数组。
各类背包的一维优化写法对比:
| 类型 | j 遍历顺序 | 解释 |
|---|---|---|
| 0-1 背包 | for j from W down to w[i] | 倒序:防止多次选择同一物品 |
| 完全背包 | for j from w[i] to W | 正序:允许重复使用当前物品 |
| 多重背包(二进制拆分) | 拆成若干个 0-1 物品后处理 | 防止超时 |
五、例题归类(每种类型都附带一个经典应用)
| 背包类型 | 题目示例 | 描述 |
|---|---|---|
| 0-1 背包 | 经典最大价值问题 | n 件物品,每个选一次,背包容量为 W |
| 完全背包 | 硬币兑换 | 无限数量的硬币组成目标金额 |
| 多重背包 | 商品选购 | 每种商品有库存限制 |
| 分组背包 | 项目选择 | 每类项目只能选一个,例如 CPU/显卡/内存 各选一个 |
| 混合背包 | 商店打折组合 | 有些商品有限,有些无限 |
| 二维背包 | 同时限制金钱和时间 | 如同时给出“时间限制”和“重量限制” |
六、注意事项 & 常见错误
| 问题 | 错误描述 | 正确做法 |
|---|---|---|
| 遍历顺序写错 | 完全背包使用倒序 | 完全背包需正序遍历 j |
| 状态转移写错 | 忘了判断 j >= w[i] | 加上条件判断 |
| 多重背包暴力写法超时 | 三重循环 | 用二进制拆分优化 |
| 使用二维数组时初始化错 | 未初始化第 0 行 | 初始化 dp[0][*] 为 0 |
七、总结口诀
背包问题口诀:
多个物品选几个,容量限制是核心;
选或不选看约束,价值最大找最优;
可重复用正序扫,只能选一次就倒流;
多重拆成 0-1 背,分组记得内部分组选。