0/1 背包最大价值问题 | 豆包MarsCode AI刷题

74 阅读3分钟

0/1 背包问题题解

问题描述

0/1 背包问题是动态规划中的经典问题之一。问题描述如下:一个旅行者外出旅行时需要将 n 件物品装入背包,背包的总容量为 m。每个物品都有一个重量和一个价值。我们需要根据这些物品的重量和价值,决定如何选择物品放入背包,使得在不超过总容量的情况下,背包中物品的总价值最大。

给定两个整数数组 weights 和 values,其中 weights[i] 表示第 i 个物品的重量,values[i] 表示第 i 个物品的价值。我们需要输出在满足背包总容量为 m 的情况下,背包中物品的最大总价值。

解题思路

1. 问题理解

首先,我们需要理解问题的核心:在有限的背包容量下,如何选择物品使得总价值最大化。这是一个典型的组合优化问题,可以通过动态规划来解决。

2. 数据结构选择

为了解决这个问题,我们可以使用一个二维数组 dp,其中 dp[i][j] 表示在前 i 个物品中,背包容量为 j 时的最大价值。

3. 算法步骤
  1. 初始化

    • 创建一个 (n+1) x (m+1) 的二维数组 dp,并将所有元素初始化为0。dp[0][j] 表示没有任何物品时,背包容量为 j 的最大价值,显然为0。
  2. 状态转移

    • 对于每个物品 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]

  3. 结果输出

    • 最终的结果是 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 背包问题是一个经典的动态规划问题,通过定义状态和状态转移方程,我们可以有效地解决这个问题。动态规划的核心思想是将大问题分解为小问题,并通过记忆化中间结果来避免重复计算。通过合理的状态设计和状态转移,我们可以在多项式时间内解决这个问题。