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

111 阅读4分钟

0,1背包最大价值问题 - MarsCode

问题描述

一个旅行者外出旅行时需要将 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 背包问题。我们需要通过选择若干个物品放入背包,使得背包中的物品总重量不超过给定的容量,并且总价值最大。

问题分析

  • 我们有 n 个物品,每个物品有两个属性:重量 weights[i] 和价值 values[i]
  • 背包的容量是 m,我们的目标是选择一些物品放入背包,保证背包总容量不超过 m,并使得背包中物品的总价值最大。

动态规划解法

我们可以使用动态规划来解决这个问题。设 dp[i][j] 表示前 i 个物品中,放入总重量不超过 j 的情况下,能得到的最大价值。

状态转移方程
  • 不选第 i 个物品时,dp[i][j] = dp[i-1][j]
  • 选第 i 个物品时,dp[i][j] = dp[i-1][j - weights[i]] + values[i],前提是 j >= weights[i]

最终的答案就是 dp[n][m],即在考虑所有物品的情况下,背包容量为 m 时的最大价值。

优化

可以使用一维数组来优化空间,因为 dp[i][j] 只与 dp[i-1][j]dp[i-1][j - weights[i]] 相关,因此可以用一个一维数组 dp[j] 来代替二维数组。

def solution(n, weights, values, m): # dp[i] 表示容量为 i 的背包可以获得的最大价值 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])

return dp[m]

测试用例

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

def solution(n, weights, values, m):
    # dp[i] 表示容量为 i 的背包可以获得的最大价值
    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])

    return dp[m]

# 测试用例
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 的背包能够获得的最大价值,初始化时,所有容量的最大价值都为 0,因为初始时没有任何物品。
  2. 动态规划更新

    • 对每个物品 i,从背包的最大容量 m 开始倒序遍历容量 j(这样做是为了避免在同一物品计算时重复使用它)。
    • 对于每个容量 j,更新 dp[j] 为不放第 i 个物品和放第 i 个物品两种情况下的最大价值。
  3. 返回结果

    • 最终,dp[m] 就是容量为 m 时的最大价值。

时间复杂度

  • 时间复杂度: O(n * m),其中 n 是物品数量,m 是背包容量。我们需要遍历所有物品,并且对于每个物品遍历所有可能的容量。
  • 空间复杂度: O(m),使用了一维数组 dp 来存储每个容量下的最大价值。

测试用例

  1. 样例 1

    输入:

    python
    复制代码
    solution(3, [2, 1, 3], [4, 2, 3], 3)
    

    输出:

    复制代码
    6
    

    解释:选择物品 1 和物品 3(重量分别为 2 和 3,总重量为 3,总价值为 6),最大价值为 6。

  2. 样例 2

    输入:

    python
    复制代码
    solution(4, [1, 2, 3, 2], [10, 20, 30, 40], 5)
    

    输出:

    复制代码
    70
    

    解释:选择物品 4(重量 2,价值 40)和物品 3(重量 3,价值 30),总重量为 5,总价值为 70。

  3. 样例 3

    输入:

    python
    复制代码
    solution(2, [1, 4], [5, 10], 4)
    

    输出:

    复制代码
    10
    

    解释:选择物品 2(重量 4,价值 10),最大价值为 10。