背包问题总结
背包问题
0/1背包
有\(n\)个物品,每个物品有一个体积\(v\),价值\(w\),每个物品只能选一次,问在所选体积不超过\(m\)的情况下的最大价值
枚举每个物品选或不选
设\(f[i,j]\)表示前\(i\)件物品,选的体积不超过\(j\)的最大价值
-
初始化 \(f[0,[0,m]] = 0\)
-
转移
\[f[i,j] = max(f[i-1,j],f[i-1,j-v_i]+w_i)
\]
- 目标 \(f[n,m]\)
倒序循环\(j\)可滚动数组优化空间
注意:如果\(f[i,j]\)的定义是选的体积等于\(j\)的最大价值,那么
- 初始化 \(f[0,[1,m]] = inf,f[0,0] = 0\)
- 目标 \(\max\{f[n,i]\},0 \leq i \leq m\)
如果题目要求等于\(m\)就只能用第二种定义,相应的目标就为\(f[n,m]\)
完全背包
每个物品可选无数次
滚动并正序循环\(j\)即可
注意的地方同上
多重背包
每个物品有\(c\)个
- 二进制拆分
- 单调队列优化
for(in(n),in(m),i = 1;i <= n; ++i) {
for(in(w),in(v),in(c),j = 0;j < v; ++j) {
l = 1,r = 0,lim = (m-j)/v;
for(k = 0;k <= lim; ++k) {
while(l <= r && q[r].v <= f[k*v+j]-k*w) --r;
q[++r] = qwq {k,f[k*v+j]-k*w};
while(l <= r && q[l].pos < k-c) ++l;
if(l <= r) f[k*v+j] = q[l].v+k*w;
}
}
}
out(f[m]);
分组背包
每组至多选一个物品