派派的刷题之旅(六) | 豆包MarsCode AI 刷题

45 阅读3分钟

0,1背包最大价值问题

问题描述

一个旅行者外出旅行时需要将 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

思路解析

  1. 定义状态:我们可以使用一个二维数组 dp,其中 dp[i][j] 表示在前 i 个物品中,背包容量为 j 时的最大价值。

  2. 状态转移方程

    • 如果不选择第 i 个物品,那么 dp[i][j] = dp[i-1][j]
    • 如果选择第 i 个物品,那么 dp[i][j] = dp[i-1][j-weights[i]] + values[i]
    • 最终的状态转移方程为:dp[i][j] = max(dp[i-1][j], dp[i-1][j-weights[i]] + values[i])
  3. 初始化dp[0][j] 应该初始化为0,因为没有任何物品时,最大价值为0。

  4. 最终结果dp[n][m] 即为所求的最大价值。

解题代码

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]

复杂度分析

时间复杂度分析

当前代码使用了动态规划的方法来解决0/1背包问题。具体的时间复杂度分析如下:

  1. 外层循环:遍历每个物品,循环次数为 n
  2. 内层循环:遍历每个可能的背包容量,循环次数为 m

因此,总的时间复杂度为 O(n * m),其中 n 是物品的数量,m 是背包的容量。

空间复杂度分析

当前代码使用了一个二维数组 dp 来存储中间结果。具体的空间复杂度分析如下:

  1. 二维数组 dpdp 的大小为 (n+1) x (m+1),因此空间复杂度为 O(n * m)

总结

  • 时间复杂度O(n * m)
  • 空间复杂度O(n * m)

总结与思考

状态转移方程

  • 如果不选择第 i 个物品,那么 dp[i][j] = dp[i-1][j]
  • 如果选择第 i 个物品,那么 dp[i][j] = dp[i-1][j-weights[i]] + values[i]
  • 最终的状态转移方程为:dp[i][j] = max(dp[i-1][j], dp[i-1][j-weights[i]] + values[i])