问题描述
一个旅行者外出旅行时需要将 n 件物品装入背包,背包的总容量为 m。每个物品都有一个重量和一个价值。你需要根据这些物品的重量和价值,决定如何选择物品放入背包,使得在不超过总容量的情况下,背包中物品的总价值最大。
给定两个整数数组 weights 和 values,其中 weights[i] 表示第 i 个物品的重量,values[i] 表示第 i 个物品的价值。你需要输出在满足背包总容量为 m 的情况下,背包中物品的最大总价值。
问题理解
你有一个背包,背包的总容量为 m。你有 n 个物品,每个物品有一个重量和一个价值。你需要选择一些物品放入背包,使得在不超过背包总容量的情况下,背包中物品的总价值最大。
数据结构选择
-
动态规划(DP):这是一个典型的0-1背包问题,可以使用动态规划来解决。
-
DP数组:我们可以使用一个一维数组
dp,其中dp[j]表示背包容量为j时的最大价值。
算法步骤
-
初始化:创建一个长度为
m+1的数组dp,用于存储不同背包容量下的最大价值,并将所有元素初始化为0。 -
状态转移:
- 对于每个物品 i,从背包容量 m 递减到物品重量 weights[i],更新 dp 数组。
- 更新公式为:dp[j] = max(dp[j], dp[j - weights[i]] + values[i])。
- 返回结果:最终
dp[m]就是背包容量为m时的最大价值。
代码框架
def solution(weights, values, m):
# 初始化 dp 数组
dp = [0] * (m + 1)
# 遍历每个物品
for i in range(len(weights)):
# 从背包容量 m 递减到物品重量
for j in range(m, weights[i] - 1, -1):
# 状态转移
dp[j] = max(dp[j], dp[j - weights[i]] + values[i])
return dp[m] # 返回背包容量为 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### 问题理解
动态规划(DP)
让我们详细解释一下为什么这个问题可以使用动态规划(DP)来解决,并且为什么它是一个典型的0-1背包问题。
动态规划是一种通过将问题分解为子问题并存储子问题的解来解决复杂问题的方法。它通常用于优化问题,其中问题的解可以通过组合子问题的解来获得。
·0-1背包问题
0-1背包问题是动态规划中的一个经典问题。在这个问题中,你有一个背包,背包的总容量为 m,以及 n 个物品,每个物品有一个重量和一个价值。你需要选择一些物品放入背包,使得在不超过背包总容量的情况下,背包中物品的总价值最大。
·为什么是0-1背包问题?
-
每个物品只能选择一次:在0-1背包问题中,每个物品要么被选中放入背包,要么不被选中。你不能多次选择同一个物品。
-
容量限制:背包有一个固定的容量
m,你需要在不超过这个容量的前提下,最大化背包中物品的总价值。
·动态规划的适用性
-
最优子结构:0-1背包问题具有最优子结构性质。也就是说,问题的最优解可以通过子问题的最优解来构造。
-
重叠子问题:在计算过程中,许多子问题会被重复计算。动态规划通过存储这些子问题的解来避免重复计算,从而提高效率。
·动态规划的步骤
-
定义状态:我们定义
dp[j]表示背包容量为j时的最大价值。 -
状态转移方程:对于每个物品
i,我们有两种选择:
- 不选择物品 i:dp[j] 保持不变。
- 选择物品 i:dp[j] = dp[j - weights[i]] + values[i]。
最终的状态转移方程为:dp[j] = max(dp[j], dp[j - weights[i]] + values[i])。
-
初始化:将
dp数组初始化为0。 -
计算:从背包容量
m递减到物品重量weights[i],更新dp数组。 -
结果:最终
dp[m]就是背包容量为m时的最大价值。