AcWing 01背包问题是一个经典的动态规划问题。问题描述通常是这样的:给定一组物品,每种物品都有自己的重量和价值。在限定的总重量内,我们如何选择,才能使得物品的总价值最大。
思路
-
状态定义:定义
dp[i][j]
为前i
个物品中,选择总重量不超过j
的物品所能得到的最大价值。 -
状态转移方程:对于第
i
个物品,有两种选择:选或不选。- 如果不选第
i
个物品,则dp[i][j] = dp[i-1][j]
(即前i-1
个物品在总重量不超过j
时的最大价值)。 - 如果选第
i
个物品,则dp[i][j] = dp[i-1][j-weight[i]] + value[i]
(其中weight[i]
和value[i]
分别是第i
个物品的重量和价值)。注意,这里的前提是j >= weight[i]
,即当前的总重量j
要能够容纳第i
个物品。 - 综上,状态转移方程为:
dp[i][j] = max(dp[i-1][j], dp[i-1][j-weight[i]] + value[i])
,但注意当j < weight[i]
时,只能选择不选第i
个物品。
- 如果不选第
-
初始化:通常将
dp
数组的所有元素初始化为0,但也可以只初始化第一行和第一列。 -
结果:最终答案为
dp[n][W]
,其中n
是物品的数量,W
是限定的总重量。
C++ 代码
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
const int N = 1010; // 假设物品数量和总重量都不会超过1000
int main() {
int n, W; // n为物品数量,W为限定的总重量
cin >> n >> W;
vector<int> weight(n + 1), value(n + 1); // weight[i]表示第i个物品的重量,value[i]表示第i个物品的价值
for (int i = 1; i <= n; i++) {
cin >> weight[i] >> value[i];
}
vector<vector<int>> dp(n + 1, vector<int>(W + 1, 0)); // dp数组
for (int i = 1; i <= n; i++) {
for (int j = 0; j <= W; j++) {
if (j >= weight[i]) {
dp[i][j] = max(dp[i - 1][j], dp[i - 1][j - weight[i]] + value[i]);
} else {
dp[i][j] = dp[i - 1][j];
}
}
}
cout << dp[n][W] << endl; // 输出最大价值
return 0;
}
注意:这个代码是二维动态规划的实现。在实际应用中,我们还可以优化空间复杂度,使用一维动态规划来求解,因为dp[i][j]
只与dp[i-1][...]
有关。