0/1 背包问题 | 豆包MarsCode AI刷题

61 阅读4分钟

问题描述

一个旅行者外出旅行时需要将 n 件物品装入背包,背包的总容量为 m。每个物品都有一个重量和一个价值。你需要根据这些物品的重量和价值,决定如何选择物品放入背包,使得在不超过总容量的情况下,背包中物品的总价值最大。

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


测试样例

样例1:

输入:n = 3 ,weights = [2, 1, 3] ,values = [4, 2, 3] ,m = 3
输出:6

样例2:

输入:n = 4 ,weights = [1, 2, 3, 2] ,values = [10, 20, 30, 40] ,m = 5
输出:70

样例3:

输入:n = 2 ,weights = [1, 4] ,values = [5, 10] ,m = 4
输出:10

这是经典的 0/1 背包问题,目标是在给定物品的重量和价值的情况下,选择哪些物品放入背包,使得背包的总价值最大,并且背包的总重量不超过容量限制。

问题分析

  • 每个物品有一个重量 weights[i] 和一个价值 values[i]
  • 背包的容量为 m,我们需要选择一些物品放入背包,要求不超过容量 m,同时背包中物品的总价值最大。

动态规划解法

我们可以使用 动态规划 来解决这个问题。动态规划的思路如下:

  1. 使用一个数组 dp,其中 dp[j] 表示背包容量为 j 时,能够获得的最大价值。
  2. 我们初始化 dp[0] = 0,表示容量为 0 时,背包中的价值为 0。
  3. 对于每个物品 i,我们尝试放入背包,并更新相应的 dp[j],其中 j 是背包的容量。我们需要逆序更新 dp,避免在更新 dp 时使用同一个物品多次。
  4. 对于每个容量 j(从大到小),如果当前物品 i 的重量 weights[i] 小于等于 j,我们就尝试将物品放入背包,更新最大价值为 dp[j] = max(dp[j], dp[j - weights[i]] + values[i])

代码实现

python
复制代码
def solution(n: int, weights: list, values: list, m: int) -> int:
    # dp[j] 表示容量为 j 的背包所能获得的最大价值
    dp = [0] * (m + 1)
    
    # 遍历每个物品
    for i in range(n):
        # 从背包最大容量 m 开始,逐渐往小容量更新,防止重复选择
        for j in range(m, weights[i] - 1, -1):
            dp[j] = max(dp[j], dp[j - weights[i]] + values[i])
    
    # 最后返回最大容量 m 时的最大价值
    return dp[m]

# 测试用例
if __name__ == '__main__':
    print(solution(3, [2, 1, 3], [4, 2, 3], 3))  # 6
    print(solution(4, [1, 2, 3, 2], [10, 20, 30, 40], 5))  # 70
    print(solution(2, [1, 4], [5, 10], 4))  # 10

解释

  1. dp数组dp[j] 表示容量为 j 的背包能够获得的最大价值。初始化时,dp[0] 为 0,表示背包容量为 0 时没有物品可以放入,因此最大价值为 0。
  2. 物品选择:对于每个物品,我们从背包容量的最大值 m 开始,逐步向小容量更新 dp。我们从大到小更新是为了避免同一个物品被多次选取。
  3. 状态转移:对于每个物品 i,如果背包当前容量 j 大于等于物品的重量 weights[i],则可以选择放入该物品,更新最大价值为 dp[j] = max(dp[j], dp[j - weights[i]] + values[i])
  4. 最终结果:在遍历所有物品后,dp[m] 就是背包容量为 m 时能够获得的最大价值。

时间复杂度

  • 时间复杂度:O(n * m),其中 n 是物品的数量,m 是背包的容量。我们需要遍历所有物品,对于每个物品,我们遍历背包容量从 m 到 weights[i]
  • 空间复杂度:O(m),我们只需要一个大小为 m+1 的数组 dp 来存储最大价值。

测试结果

  • 对于输入 n = 3, weights = [2, 1, 3], values = [4, 2, 3], m = 3,输出应为 6
  • 对于输入 n = 4, weights = [1, 2, 3, 2], values = [10, 20, 30, 40], m = 5,输出应为 70
  • 对于输入 n = 2, weights = [1, 4], values = [5, 10], m = 4,输出应为 10

这样就能够解决这个背包问题,得出最大价值。