01 背包问题
题目描述
第一问: 求这个背包至多能装多大价值的物品? 第二问: 若背包恰好装满,求至多能装多大价值的物品?
输入示例:
3 5
2 10
4 5
1 4
输出示例:
14
9
说明: 装第一个和第三个物品时总价值最大(14),但装第二个和第三个物品可以使得背包恰好装满且总价值最大(9)。
备注: 要求 O(nV) 的时间复杂度,O(V) 空间复杂度。
动态规划解法
第一问:至多能装多大价值
1. 状态表示
01 背包问题本质上是线性 DP 问题。使用二维定义:
dp[i][j] 表示在前 i 个位置中选择物品,物品总体积不超过 j 的所有选法中能选出来的最大价值。
2. 状态转移方程
根据最后一个位置是否选择来划分问题:
i物品不选:dp[i][j] = dp[i-1][j]i物品要选:需要保证剩余容量大于等于 0,即j - v[i] >= 0,则dp[i][j] = w[i] + dp[i-1][j - v[i]]综合为:dp[i][j] = Math.max(dp[i-1][j], w[i] + dp[i-1][j - v[i]])
3. 初始化
选择物品是从下标 1 开始的,到 n 结束,那么 dp 表就需要多创建一行一列。
- 第一行表示没有物品可选,总体积不超过 j 的最大价值。既然没有物品,那就不选,全都为 0。
- 第一列表示所选物品总体积不超过 0 的最大价值。此时最大价值就是 0,不选即可,全都为 0。
4. 填表顺序
根据状态转移方程可知,要想得到 dp[i][j] 就得先知道 dp[i-1][j] 或者 dp[i-1][j-v[i]],所以应该从上往下填写每一行,从左往右填写每一列。
5. 返回值
打印 dp[n][V] 即可。
第二问:恰好装满
1. 状态表示
二维定义 dp[i][j] 表示在前 i 个位置中选择物品,物品总体积刚好为 j 的所有选法中能选出来的最大价值。
可能存在所有选法都不能恰好装满背包,我们规定此时 dp[i][j] = -1。
2. 状态转移方程
根据最后一个位置是否选择来划分问题:
i物品不选:dp[i][j] = dp[i-1][j]i物品要选:需要保证剩余容量大于等于 0,且前一步状态有效(不为 -1),即j - v[i] >= 0 && dp[i-1][j - v[i]] != -1。 综合为:dp[i][j] = Math.max(dp[i-1][j], w[i] + dp[i-1][j - v[i]])
3. 初始化
- 第一行表示没有物品可选,总体积等于 j 的最大价值。
dp[0][0] = 0,后面无论选不选,总价值都达不到 j,于是全都初始化为 -1。


