0、1背包问题
题目描述
一个旅行者外出旅行时需要将 nnn 件物品装入背包,背包的总容量为 mmm。每个物品都有一个重量和一个价值。你需要根据这些物品的重量和价值,决定如何选择物品放入背包,使得在不超过总容量的情况下,背包中物品的总价值最大。
给定两个整数数组 weights 和 values,其中 weights[i] 表示第 iii 个物品的重量,values[i] 表示第 iii 个物品的价值。你需要输出在满足背包总容量为 mmm 的情况下,背包中物品的最大总价值。
题目解析
这个问题是经典的“0/1背包问题”,它要求我们在一个固定容量的背包中选择物品,使得物品的总价值最大。这里的挑战在于如何在给定的容量和物品之间做出选择,以使背包中物品的总价值最大化。
我们可以采用动态规划(Dynamic Programming,DP)的方法来解决这个问题。动态规划方法可以通过状态转移方程在 O(n×m)O(n \times m)O(n×m) 的时间复杂度内解决问题,适用于背包容量较大时。
方法介绍
为了求解这个背包问题,我们可以使用一个二维数组 dp[i][j],其中 i 表示前 iii 个物品,j 表示背包的容量。dp[i][j] 的含义是:前 iii 个物品在容量为 jjj 的背包中能取得的最大价值。
状态转移方程
对于每个物品 iii 和背包容量 jjj,我们有两种选择:
- 不放入背包:此时,
dp[i][j] = dp[i-1][j]。 - 放入背包:此时,
dp[i][j] = dp[i-1][j - weight[i]] + value[i],前提是 j≥weight[i]j \geq weight[i]j≥weight[i]。
最终,dp[n][m] 就是我们所需要的最大价值。
动态规划实现
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
int knapsack(int m, const vector<int>& weights, const vector<int>& values) {
int n = weights.size();
vector<vector<int>> dp(n + 1, vector<int>(m + 1, 0)); // dp[i][j]表示前i个物品放入容量为j的背包的最大价值
// 动态规划求解
for (int i = 1; i <= n; ++i) {
for (int j = 1; j <= m; ++j) {
// 不放第i个物品
dp[i][j] = dp[i - 1][j];
// 放第i个物品
if (j >= weights[i - 1]) {
dp[i][j] = max(dp[i][j], dp[i - 1][j - weights[i - 1]] + values[i - 1]);
}
}
}
// dp[n][m]是我们想要的最大总价值
return dp[n][m];
}
int main() {
vector<int> weights = {2, 3, 4, 5}; // 每个物品的重量
vector<int> values = {3, 4, 5, 6}; // 每个物品的价值
int m = 5; // 背包容量
cout << "最大价值为: " << knapsack(m, weights, values) << endl;
return 0;
}
代码解析
输入:我们首先定义了物品的重量数组 weights 和价值数组 values,以及背包的总容量 m。
DP数组:我们用二维数组 dp 来记录每一个状态的最大价值。dp[i][j] 表示使用前 iii 个物品,容量为 jjj 的背包所能获得的最大价值。
状态转移:对于每个物品 iii 和背包容量 jjj,我们有两种选择:
不放该物品:`dp[i][j] = dp[i - 1][j]`。
放该物品:如果背包容量 j≥weights[i−1]j \geq weights[i-1]j≥weights[i−1],那么 `dp[i][j] = max(dp[i][j], dp[i - 1][j - weights[i - 1]] + values[i - 1])`。
最终结果:dp[n][m] 表示前 nnn 个物品在容量为 mmm 的背包中可以获得的最大价值。
代码演示
假设我们有以下数据:
物品的重量:{2, 3, 4, 5}
物品的价值:{3, 4, 5, 6}
背包容量:5
输出:
最大价值为: 7
这个结果表示,在容量为 5 的背包中,选择前两个物品(重量为 2 和 3,价值分别为 3 和 4),能够获得的最大总价值为 7。
时间复杂度分析
动态规划算法的时间复杂度为 O(n×m)O(n \times m)O(n×m),其中 nnn 是物品的数量,mmm 是背包的容量。这个时间复杂度对于大部分背包问题来说已经是相当高效的,尤其是在背包容量 mmm 较大时。
总结
这个问题是典型的“背包问题”,使用动态规划(DP)是解决这类问题的一种常见且高效的方法。通过定义状态转移方程,我们能够逐步计算出背包中物品的最大总价值。