01背包问题
20240220算法入门👉🏻AcWing
问题描述
有n件物品和一个最大容积为V的背包。第i件物品的体积是v[i],得到的价值是w[i] 。每件物品只能用一次,求解将哪些物品装入背包里物品价值总和最大。
代码详解
|
|
想要解释这段代码的思路,核心就是理解其动态规划状态转移方程: $$ dp[i][j] = max(dp[i-1][j], dp[i-1][j-v[i]]+w[i]); $$ dp数组示例(3件物品,容量最大为4):
容量0(j=0) | 容量1(j=1) | 容量2(j=2) | 容量3(j=3) | 容量4(j=4) | |
---|---|---|---|---|---|
不选择物品(i=0) | 0 | 0 | 0 | 0 | 0 |
物品1(i=1) | 0 | ||||
物品2(i=2) | 0 | ||||
物品3(i=3) | 0 |
该二维数组每一项值dp[i][j]均表示在从下标[0,i]的物品里符合要求的任取后放进容量为j的背包下最大的价值总和。换句话理解就是表格中的每一项都是当前情况下的最优解(最大价值)。
值得强调的是在构建二维数组时要考虑i=0和j=0的情况,即什么都不选和背包容量为0,方便状态转移方程进行递推,易得第一行和第一列值均为0。
接下来就是按行依次进行递推,考虑每格的值就两种情况:
-
不放入物品i,就相当于和之前情况无变化,即此情况下最优与上面一格相同(dp[i-1][j])。
-
放入物品i,需先考虑能否放入(主要比较容积,不能放入的话回到情况1),能放入的话无非就是比较放入后的价值和不放入的价值哪个更大,即状态转移方程中max(dp[i-1][j],xxxx)部分可以理解了,现在就是如何计算放入当前物品后的最优价值。
因为我要放入该物品i,则还剩下的背包空间为j-v[i],则要找到背包空间为j-v[i]下的不含物品i的最优价值即dp[i-1][j-v[i]],再加上物品i的价值即为所求,状态转移方程dp[i-1][j-v[i]]+w[i]部分由此而来。
由此完成所有递推,dp[n][V]即为最终的最大价值。
👉🏻学习参考链接中有提到优化版,不多赘述,其思路主要是原方案下只用到了当前行(i)和前一行(i-1),因此将二维简化到了一维,将每一次大循环后所得到的dp[N]理解为原先二维中的某一行即可 。原先二维可以理解为把每一步物品选择后的最优价值都进行了存储,优化版本则放弃了存储的冗余,每一步递推都在原数组上直接进行并覆盖。