二维费用背包
二维费用背包
一、问题描述
有 件物品,第 件物品的重量为 ,体积为 ,价值为 ,每件物品最多选择一次。
背包的重量上限为 ,体积上限为 。求总重量不超过 、总体积不超过 时,能够得到的最大总价值。
与普通 01 背包相比,只是增加了一种资源限制,因此也称为二维费用的 01 背包。这里的“二维”指两种费用,而不是 DP 数组的维数。
二、状态与转移
设 表示:只考虑前 件物品,重量不超过 、体积不超过 时的最大总价值。
仍然枚举第 件物品选或不选:
$$dp[i][j][k]=\max\left( dp[i-1][j][k],\quad dp[i-1][j-w[i]][k-c[i]]+v[i] \right).$$第二项要求 且 ,否则只能不选。
允许不选任何物品,因此 。答案为 。
三、压缩物品维度
省去第一维,使用 dp[j][k] 保存状态,转移为:
dp[j][k] = max(dp[j][k], dp[j - w][k - c] + v);
两个容量统一倒序枚举。 这样转移来源仍保存上一轮的状态,保证当前物品最多选择一次。
输入第一行为 ,接下来 行,每行输入一件物品的重量、体积和价值。输出最大总价值。
#include <iostream>
#include <algorithm>
#include <vector>
using namespace std;
int main() {
ios::sync_with_stdio(false);
cin.tie(nullptr);
int n, W, C;
cin >> n >> W >> C;
vector<vector<long long>> dp(W + 1, vector<long long>(C + 1, 0));
for (int i = 1; i <= n; ++i) {
int w, c;
long long v;
cin >> w >> c >> v;
for (int j = W; j >= w; --j) {
for (int k = C; k >= c; --k) {
dp[j][k] = max(dp[j][k], dp[j - w][k - c] + v);
}
}
}
cout << dp[W][C] << '\n';
return 0;
}
时间复杂度为 ,空间复杂度为 ,容量为正时通常简写为 和 。