0/1 背包问题题解
问题描述
0/1 背包问题是动态规划中的经典问题之一。问题描述如下:一个旅行者外出旅行时需要将 n 件物品装入背包,背包的总容量为 m。每个物品都有一个重量和一个价值。我们需要根据这些物品的重量和价值,决定如何选择物品放入背包,使得在不超过总容量的情况下,背包中物品的总价值最大。
给定两个整数数组 weights 和 values,其中 weights[i] 表示第 i 个物品的重量,values[i] 表示第 i 个物品的价值。我们需要输出在满足背包总容量为 m 的情况下,背包中物品的最大总价值。
解题思路
1. 问题理解
首先,我们需要理解问题的核心:在有限的背包容量下,如何选择物品使得总价值最大化。这是一个典型的组合优化问题,可以通过动态规划来解决。
2. 数据结构选择
为了解决这个问题,我们可以使用一个二维数组 dp,其中 dp[i][j] 表示在前 i 个物品中,背包容量为 j 时的最大价值。
3. 算法步骤
-
初始化:
- 创建一个
(n+1) x (m+1)的二维数组dp,并将所有元素初始化为0。dp[0][j]表示没有任何物品时,背包容量为j的最大价值,显然为0。
- 创建一个
-
状态转移:
-
对于每个物品
i(从1到n),我们遍历所有可能的背包容量j(从0到m)。 -
如果当前物品的重量
weights[i-1]小于等于背包容量j,我们可以选择将该物品放入背包或不放入背包。- 如果选择放入背包,那么
dp[i][j] = dp[i-1][j-weights[i-1]] + values[i-1]。 - 如果不选择放入背包,那么
dp[i][j] = dp[i-1][j]。 - 最终的
dp[i][j]应该是这两种选择中的最大值。
- 如果选择放入背包,那么
-
如果当前物品的重量
weights[i-1]大于背包容量j,那么我们只能选择不放入背包,即dp[i][j] = dp[i-1][j]。
-
-
结果输出:
- 最终的结果是
dp[n][m],即在前n个物品中,背包容量为m时的最大价值。
- 最终的结果是
4. 代码实现
以下是基于上述思路的Python代码实现:
def solution(n: int, weights: list, values: list, m: int) -> int:
# 初始化一个 (n+1) x (m+1) 的二维数组 dp,初始值为0
dp = [[0] * (m + 1) for _ in range(n + 1)]
# 遍历每个物品
for i in range(1, n + 1):
for j in range(m + 1):
# 如果当前物品的重量小于等于背包容量
if weights[i - 1] <= j:
# 选择当前物品和不选择当前物品的最大值
dp[i][j] = max(dp[i - 1][j], dp[i - 1][j - weights[i - 1]] + values[i - 1])
else:
# 不选择当前物品
dp[i][j] = dp[i - 1][j]
# 返回最大价值
return dp[n][m]
复杂度分析
- 时间复杂度:
O(n * m),其中n是物品的数量,m是背包的容量。我们需要遍历每个物品和每个可能的背包容量。 - 空间复杂度:
O(n * m),我们使用了一个(n+1) x (m+1)的二维数组来存储中间结果。
总结
0/1 背包问题是一个经典的动态规划问题,通过定义状态和状态转移方程,我们可以有效地解决这个问题。动态规划的核心思想是将大问题分解为小问题,并通过记忆化中间结果来避免重复计算。通过合理的状态设计和状态转移,我们可以在多项式时间内解决这个问题。