问题描述
一个旅行者外出旅行时需要将 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
解释
-
初始化 dp 数组:
dp[j]表示容量为j的背包能够获得的最大价值,初始化时,所有容量的最大价值都为 0,因为初始时没有任何物品。
-
动态规划更新:
- 对每个物品
i,从背包的最大容量m开始倒序遍历容量j(这样做是为了避免在同一物品计算时重复使用它)。 - 对于每个容量
j,更新dp[j]为不放第i个物品和放第i个物品两种情况下的最大价值。
- 对每个物品
-
返回结果:
- 最终,
dp[m]就是容量为m时的最大价值。
- 最终,
时间复杂度
- 时间复杂度: O(n * m),其中
n是物品数量,m是背包容量。我们需要遍历所有物品,并且对于每个物品遍历所有可能的容量。 - 空间复杂度: O(m),使用了一维数组
dp来存储每个容量下的最大价值。
测试用例
-
样例 1:
输入:
python 复制代码 solution(3, [2, 1, 3], [4, 2, 3], 3)输出:
复制代码 6解释:选择物品 1 和物品 3(重量分别为 2 和 3,总重量为 3,总价值为 6),最大价值为 6。
-
样例 2:
输入:
python 复制代码 solution(4, [1, 2, 3, 2], [10, 20, 30, 40], 5)输出:
复制代码 70解释:选择物品 4(重量 2,价值 40)和物品 3(重量 3,价值 30),总重量为 5,总价值为 70。
-
样例 3:
输入:
python 复制代码 solution(2, [1, 4], [5, 10], 4)输出:
复制代码 10解释:选择物品 2(重量 4,价值 10),最大价值为 10。