背包入门
本文最后更新于:2024年4月10日 下午
背包笔记
01背包问题
题目:有N件物品和一个容量为V的背包。第i件物品的费用是v[i],价值是w[i]。求解将哪些物品装入背包可使这些物品的费用总和不超过背包容量,且价值总和最大。
这是最基础的背包问题,后面的背包问题都由01背包问题衍生。问题的特点是:每种物品仅有一件,只能选择放或不放。
如果这个问题采用枚举的思想,他的时间复杂度为$O(n^2)$,我们可以利用一张二维表记录数据,运用递推,这样时间复杂度就降低为$O(N*V)$
基本思路:用子问题定义状态:即f[i][v]表示前i件物品恰放入一个容量为v的背包可以获得的最大价值。则其状态转移方程便是:f[i][v]=max{f[i-1][v],f[i-1][v-c[i]]+w[i]}。 具体来说就是我们就利用一张二位表,记录了整个题目中每一个问题的解答。
用一个例子来讲大致是什么
输入
4 5
1 2
2 4
3 4
4 5
输出
8
这个例子我们可以利用一张二维表来直观展示表示
代码
1 |
|
对于这个代码的优化,其中时间复杂度基本已经不能再优化了,我们可以将他改为一维数组,这样空间复杂度却可以优化到O(V)。
注意改成一维数组后要从后往前逆序推,如果正推一个物品会取多次,这也是完全背包的解法。
代码
1 |
|
总结
01背包问题是最基本的背包问题,它包含了背包问题中设计状态、方程的最基本思想,另外,别的类型的背包问题往往也可以转换成01背包问题求解。故一定要仔细体会上面基本思路的得出方法,状态转移方程的意义,以及最后怎样优化的空间复杂度。
完全背包问题
完全背包模型与 0-1 背包类似,与 0-1 背包的区别仅在于一个物品可以选取无限次,而非仅能选取一次。
我们可以借鉴 0-1 背包的思路,进行状态定义。其状态转移方程依然还是:f[i][v]=max{f[i-1][v],f[i-1][v-c[i]]+w[i]}
。但其推到方式与0-1背包不同
1 |
|
多重背包问题
【题目描述】
设有n种物品,每种物品有一个重量及一个价值。但每种物品的数量是无限的,同时有一个背包,最大载重量为M,今从n种物品中选取若干件(同一种物品可以多次选取),使其重量的和小于等于M,而价值的和为最大。
【输入】
第一行:两个整数,M(背包容量,M≤200)和N(物品数量,N≤30);
第2..N+1行:每行二个整数Wi,Ci,表示每个物品的重量和价值。
【输出】
仅一行,一个数,表示最大总价值。
【输入样例】
10 4
2 1
3 3
4 5
7 9
【输出样例】
12
可以用和01背包一样的方式,f[i][v]表示前i种物品恰放入一个容量为v的背包的最大价值,可以用k表示当前容量下可以装第i种物品的件数,那么k的范围应该是0≤k≤v/c[i],既然要用当前物品i把当前容量装满那需要0≤k≤v/c[i]件,其中k表示件数。
状态转移方程为:f[i][v] = max{f[i-1][v],f[i-1][j - k * c[i]] + k * w[i]}(0<=k*c[i]<=v)
基于01背包问题的代码进行简单修改,我们可以写出
1 |
|
二进制分组优化
在朴素的做法中,一个一个枚举通常效率低下,因为在逐个枚举的过程中,出现了同时选了等效的问题,我们可以对数量进行二进制分组。
例子
6=1+2+3
8=1+2+3+1
1 |
|
单调队列优化
(不会,暂时空着)
混合背包问题
混合背包就是将前面三种的背包问题混合起来,有的只能取一次,有的能取无限次,有的只能取 次。
这种题目看起来很吓人,可是只要领悟了前面几种背包的中心思想,并将其合并在一起就可以了。
参考文献
- 背包九讲 https://www.cnblogs.com/jbelial/articles/2116074.html ↩
- OI-WIKI ↩