背包问题终极归纳
五大经典背包问题的终极归纳,涵盖核心思想、算法实现、适用场景及关键对比
1. 01背包问题
特点:每件物品最多选一次
状态定义:f[i][j] 表示前i件物品在容量j下的最大价值
状态转移:
f[i][j] = max(f[i-1][j], f[i-1][j-v[i]] + w[i])
优化:
- 空间优化到一维:f[j] = max(f[j], f[j-v[i]] + w[i])
- 逆序枚举容量(防止重复选择)
适用场景:
- 物品唯一性选择(选/不选)
- 典型问题:分割等和子集、目标和
2. 完全背包问题
特点:物品无限次选择
状态转移:
f[i][j] = max(f[i-1][j], f[i][j-v[i]] + w[i])
优化:
- 一维数组 + 正序枚举容量(允许重复选择)
- 数学优化:转换为体积的gcd问题(特定场景)
适用场景:
- 物品可无限使用
- 典型问题:零钱兑换、完全平方数
3. 多重背包问题(基础版)
特点:物品有限次数选择(s[i]次)
状态转移:
for(int k=0; k<=s[i] && k*v[i]<=j; k++)
f[i][j] = max(f[i][j], f[i-1][j-k*v[i]] + k*w[i])
局限:
- 三重循环,O(N·V·S)复杂度,仅适合小数据量(S≤100)
4. 多重背包问题(二进制优化版)
核心思想:将s[i]拆分为二进制组合(1,2,4,…,剩余)
优化步骤:
1. 将每个物品拆分为log₂s[i]个新物品
2. 转化为01背包问题
复杂度:O(N·V·logS)
适用场景:
- 物品种类多且数量大(如S≤2000)
- 典型问题:大容量多重背包
5. 分组背包问题
特点:每组物品最多选一个
状态转移:
for(int k=0; k
if(v[i][k] <= j)
f[j] = max(f[j], f[j-v[i][k]] + w[i][k])
关键点:
- 容量需逆序枚举(同01背包)
- 组内物品循环在容量循环内部
适用场景:
- 具有互斥选择的物品组
- 典型问题:课程选修(多选一)
终极对比表
问题类型
选择限制
核心转移方程
空间优化要点
时间复杂度
经典问题
01背包
选0/1次
f[j]=max(f[j],f[j-v]+w)
逆序枚举j
O(NV)
分割等和子集
完全背包
无限次
f[j]=max(f[j],f[j-v]+w)
正序枚举j
O(NV)
零钱兑换
多重背包I
最多s次
枚举k次选择
二维数组
O(NVS)
小额商品采购
多重背包II
最多s次
二进制拆分+01背包
逆序枚举j
O(NVlogS)
大规模物资装载
分组背包
每组选0/1个
组内物品循环+01背包逻辑
逆序枚举j
O(NVS)
课程组合优化
核心技巧总结
状态设计:
绝大多数背包问题使用f[j]表示容量为j时的最大价值
若需记录选择方案,可增加辅助数组g[][]
枚举顺序:
逆序(01背包、分组背包):防止重复选择
正序(完全背包):允许重复选择
组内全枚举(分组背包):确保每组只选一个
优化思路:
空间优化:01/完全/分组背包均可压缩到一维
多重背包:二进制拆分是通用优化手段
贪心优化:当物品价值与体积成比例时,可贪心选择
边界处理:
初始化f[0]=0,其余为-INF(求恰好装满时的最大值)
初始化全为0(普通最大价值问题)
代码模板选择指南
小数据量(N,V≤100):直接使用基础多重背包
大数据量(N,V≤1000):优先二进制优化
存在特殊约束:
需要恰好装满 → 修改初始化
求方案数 → 将max改为+=
求具体方案 → 记录状态转移路径
随便看看
- 2025-05-05 20:47:46怎么刷快手粉丝,让你的账号快速涨粉
- 2025-05-09 20:42:38如何制作原创音乐
- 2025-05-03 23:59:56秒过的小贷APP没有,这10个容易审批、好下款、到账快
- 2025-05-07 04:14:43泰捷视频 电脑版 v5.1.1.1
- 2025-05-09 18:40:42《dnf》恍惚套装属性介绍
- 2025-05-08 05:35:50英语基础语法快速入门——名词
- 2025-05-03 16:26:40交通部:全国共投放1200多万辆共享单车,平均每天2700多万人次骑行
- 2025-05-03 09:48:36小米电视如何浏览网页?实用教程!
- 2025-05-03 06:47:48微聚app官方版下载
- 2025-05-03 07:22:47DNF团队制裁鸟贝和超时空每日还能打吗