背包问题总共有9种,称为背包9讲。
- 01背包问题
- 完全背包问题
- 多重背包问题
- 混合背包问题
- 二维费用的背包问题
- 分组背包问题
- 背包问题求方案数
- 求背包问题的方案
- 有依赖的背包问题
有\(N\)件物品和一个容量是\(V\)的背包。
不同背包问题的条件:每件物品只能使用一次。
第\(i\)件物品的体积是 \(v_i\),价值是 \(w_i\)。
求解将哪些物品装入背包,可使这些物品的总体积不超过背包容量,且总价值最大。 输出最大价值。
输入格式
第一行两个整数,\(N, V\)用空格隔开,分别表示物品数量和背包容积。
接下来有 \(N\) 行,每行两个整数 \(v_i, w_i\),用空格隔开,分别表示第 \(i\) 件物品的体积和价值。
输出格式
输出一个整数,表示最大价值。
数据范围
\(0<N,V≤10000\) \(0<v_i,w_i≤10000\)
输入样例
1 | 4 5 |
输出样例:
1 | 8 |
01背包问题
题目描述
有\(N\)件物品和一个容量是\(V\)的背包。
每件物品只能使用一次。
第\(i\)件物品的体积是 \(v_i\),价值是 \(w_i\)。
求解将哪些物品装入背包,可使这些物品的总体积不超过背包容量,且总价值最大。 输出最大价值。
输入格式
第一行两个整数,\(N, V\)用空格隔开,分别表示物品数量和背包容积。
接下来有 \(N\) 行,每行两个整数 \(v_i, w_i\),用空格隔开,分别表示第 \(i\) 件物品的体积和价值。
输出格式
输出一个整数,表示最大价值。
数据范围
\(0<N,V≤10000\) \(0<v_i,w_i≤10000\)
输入样例
1 | 4 5 |
输出样例:
1 | 8 |
解
状态:
状态\(f[i][j]\)表示前\(i\)个物品的总体积\(j\)下,总价值为\(f[i][j]\).
\(result = f[i][j]\)
初始状态:\(f[0][0] = 0\)
终止状态:\(f[n][m]\)
状态转移方程:
考虑第\(i\)个状态和\(i-1\)个状态间的递推关系:
不选第\(i\)个物品,\(f[i][j] = f[i-1][j]\)
选第\(i\)个物品,\(f[i][j] = f[i-1][j-v[i]] + w[i]\)
\(f[i][j] = max(f[i-1][j], f[i-1][j-v[i]]+ w[i])\)
其中\(v[i]\)是第\(i\)个物品的体积, \(w[i]\)是第\(j\)个物品的价值
1 |
|
因为状态\(i\)每次都仅依赖状态\(i-1\),故可以优化额外空间复杂度为\(O(logN)\)
1 |
|
优化输入部分后:
1 |
|
因为要依赖dp表中上一层的状态,要先更新下标比较大的dp数组元素,此时通过状态转移方程求最大值的时候还未更新下标较小的dp数组元素,即下标较小的dp数组元素还是上一层的值,所以要逆序遍历。
要保证在1维DP中计算\(f[j]\)状态时,用的是\(f[i-1][j-v[i]]\)而不是\(f[i][j-v[i]]\)的
!不能理解的时候再去看dp表,因为要保证这一层的状态依赖于上一层的状态。
e.g. 若顺序计算的话
对于 \(i=2, j=6, v[2] = 3\),
\(dp[6]=max(dp[6], dp[6-v[2]]+w[2]) = max(dp[6], dp[3] + w[2])\)
因为动态规划是第\(i\)层的状态依赖于第\(i-1\)层的。
这时,要计算\(max\)外的\(dp[6]\),要用到\(max\)内的\(dp[6], dp[3]\)。
其中\(max\)内的\(dp[6]\)是第\(i-1\)层的,是\(dp[3]\)是第\(i\)层的,故使得状态转移不满足要求,所以得逆序。
可以见 此处例子
完全背包问题
有\(N\)件物品和一个容量是\(V\)的背包。
每件物品都有无限件可用。
第\(i\)件物品的体积是 \(v_i\),价值是 \(w_i\)。
求解将哪些物品装入背包,可使这些物品的总体积不超过背包容量,且总价值最大。 输出最大价值。
输入格式
第一行两个整数,\(N, V\)用空格隔开,分别表示物品数量和背包容积。
接下来有 \(N\) 行,每行两个整数 \(v_i, w_i\),用空格隔开,分别表示第 \(i\) 件物品的体积和价值。
输出格式
输出一个整数,表示最大价值。
数据范围
\(0<N,V≤10000\) \(0<v_i,w_i≤10000\)
输入样例
1 | 4 5 |
输出样例:
1 | 10 |
解:
1 |
|
从代码上看就是,把 01背包 的代码的二重循环,由重后往前遍历,改成了重前往后遍历。
从状态转移方程上来看,通过二维DP表的形式:
\(f[i][j] = max(f[i-1][j], f[i-1][j-v[i]]+ w[i])\)
\(max(不选第i个物品,\ 选了第i个物品)\)
\(if\ j-v[i]*k <= 0 \\f[i][j] = max(f[i-1][j], f[i][j-v[i]]+ w[i], f[i][j-v[i]*2]+w[i]*2+...)\)
\(max(不选第i个物品,\ 选了第i个物品1次, \ 选了第i个物品2次, ...)\)
现在完全背包的特点恰是每种物品可选无限件,所以在考虑“加选一件第i种物品”这种策略时,却正需要一个可能已选入第i种物品的子结果f[i][v-c[i]],所以就可以并且必须采用v= 0..V的顺序循环。
或者由这个2维动态转移方程得来。
混合背包问题
References
https://www.cnblogs.com/jbelial/articles/2116074.html
https://www.bilibili.com/video/av33930433?p=1
https://www.acwing.com/solution/acwing/content/3982/