背包问题
背包问题
在解决 0-1 背包问题时,我们的目标是选择若干物品放入背包,使得背包内物品的总价值最大,同时遵循背包容量的限制。具体来说,给定一组物品,每个物品都有一个 重量 和 价值,并且背包的容量也是有限的。我们需要从这些物品中选择一些,放入容量有限的背包中,要求背包内物品的 总重量不超过背包的容量,而 总价值最大。
0-1 背包的动态规划解法:
- 设有 $n$个物品,每个物品 $i $的 价值 为 $ v[i]$,重量 为 $w[i]$,背包的最大容量为 $C$。
- 定义一个二维数组 $ dp[i][j] $,表示考虑前 $ i $ 个物品,背包容量为 $j $ 时,能够获得的最大价值。即$ dp[i][j] $ 是当前背包容量 $j $ 和物品选择方案下的最大价值。
递推公式:
-
初始化:
- $dp[0][j] = 0 $(表示没有物品时,背包的最大价值为 0)
- $dp[i][0] = 0 $(表示背包容量为 0 时,无论选择哪些物品,总价值也为 0)
-
状态转移:
对于每个物品 $ i $和每个容量 $j$:-
如果当前物品的重量 $w[i] > j$(即当前背包容量不足以容纳这个物品),那么不能放入该物品,此时的最优解就是不放物品 $i$,即:
$dp[i][j] = dp[i-1][j]$ -
如果当前物品的重量 $w[i] \leq j$(即背包容量足够容纳当前物品),有两种选择:
- 不选择物品 $i $,此时的最优解为 $dp[i-1][j] $(即与不放入该物品时的情况一样)。
- 选择物品 $ i $,此时的最优解为物品 $ i $ 的价值加上剩余容量 $j - w[i] $ 能容纳的最大价值,即 $dp[i-1][j - w[i]] + v[i] $。
这时我们需要取两者中的最大值:
$$
dp[i][j] = \max(dp[i-1][j], dp[i-1][j-w[i]] + v[i])
$$
-
总结:
- $ dp[i][j] $ 表示在考虑前 $ i $ 个物品、容量为 $ j $ 的背包时,能够获得的最大价值。
- 对于每个物品 $ i $,如果它的重量 $ w[i] $ 超过当前背包容量 $ j $,就不能选它;否则,我们就要在 选择它 或 不选择它 之间做出最优决策,选择价值更大的方案。
完整算法:
- 初始化 $ dp[0][j] = 0 $ 和 $ dp[i][0] = 0 $。
- 对每个物品 $ i $ 和每个背包容量 $ j $ 更新 $ dp[i][j] $。
- 最终答案就是 $ dp[n][C] $,表示在所有 $ n $ 个物品和容量为 $ C $ 的背包情况下,能够获得的最大价值。
图解
-
weights物品重量、values物品价值、dp用于求解的数组(初始化如下)(黄色部分是未来求解区)
-
当考虑第一件物品时:
-
考虑第二件物品时:
-
考虑第三件物品:
代码实现
KnapsackProblem
空间优化:可以通过只使用一维数组来优化空间复杂度。因为每一行的状态仅依赖于前一行的状态。(拓展)
1 | package com.yukinoshita.algorithm.dynamicProgramming; |




