背包问题
01 背包#
竞赛中心 - 蓝桥云课 (lanqiao.cn)题意概要:有 n 个物品和一个容量为 W 的背包,每个物品有重量 wi 和价值 vi 两种属性,要求选若干物品放入背包使背包中物品的总价值最大且背包中物品的总重量不超过背包的容量。
完全背包#
2.小明的背包2 - 蓝桥云课 (lanqiao.cn)完全背包模型与 0-1 背包类似,与 0-1 背包的区别仅在于一个物品可以选取无限次,而非仅能选取一次。
多重背包#
3.小明的背包3 - 蓝桥云课 (lanqiao.cn)多重背包也是 0-1 背包的一个变式。与 0-1 背包的区别在于每种物品有 ki 个,而非一个。
一个很朴素的想法就是:把「每种物品选 ki 次」等价转换为「有 ki 个相同的物品,每个物品选一次」。这样就转换成了一个 0-1 背包模型,套用上文所述的方法就可已解决。
但此时会发现再取物品 i 时每次增加一个是非常浪费时间的,时间复杂度是 O (NVK)。这时可以采用 二进制分组优化 使得时间复杂度将为 O (NVlogK)。
二进制分组优化#
具体地说就是将物品 i 的数量 k 按照二进制的方式拆分,最后不足拆分的另算一个,举几个例子 6=1+2+3 8=1+2+4+1 18=1+2+4+8+3 31=1+2+4+8+16 这样每种物品都可以分成几个,质量和价值都不相同的物品,在使用 01 背包的方式解决,二进制分组代码如下
单调队列优化#
时间复杂度 O (NV),与 01 背包相同 思路:假如由一个物品的质量是w
,价格是m
。那么在背包质量为v
时f[v]
的最大值一定是从f[v-w], f[v-2*w]... F[v-k*w]
当中的某个加上相应的能增加的价值得来的,其中 k 是该物品的个数。那么我们就可以使用单调队列优化这样的一个分组,维护改组的最大值。以此降低时间复杂度 注意:
- 不是维护组中的
f[v-i*w]
最大,而是f[v-i*w]+i*m
最大 - 在 DP 的过程中需要不断地对
f[v]
进行修改,但又要维护f
的最值,随意我们另开一个数组来备份f
数组,用来单调队列优化
代码:
二维费用背包#
这道题是很明显的 0-1 背包问题,可是不同的是选一个物品会消耗两种价值(经费、时间),只需在状态中增加一维存放第二种价值即可。
P1855 榨取kkksc03 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)
分组背包#
方法一#
这种题怎么想呢?其实是从「在所有物品中选择一件」变成了「从当前组中选择一件」,于是就对每一组进行一次 0-1 背包就可以了。
再说一说如何进行存储。我们可以将t[k][i]
表示第 k
组的第i
件物品的编号是多少,再用cnt[k]
表示第k
组物品有多少个。
P1757 通天之分组背包 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)
方法二#