问题1:01背包经典问题。
dp[i][j]表示考虑前i个物品,背包最大容量为j的时候,能装下的最大价值。
转移方程:
if (a[i] <= j) dp[i][j] = max(dp[i - 1][j], dp[i - 1][j - a[i]] + b[i]);
由于dp[i]的变化只与dp[i - 1]相关,估可以考虑从右向左遍历,使用一维数组来节约空间。
最后返回dp[n - 1][v]既可。
问题2:01背包的简单变形
dp[i][j]表示考虑前i个物品,背包刚好装满j的时候,能装下的最大价值。
考虑两种情况:
当a[i] == j的时候,这个物品可以选,既dp[i][j] = max(dp[i - 1][j], b[i]);
当a[i] < j的时候,如果dp[i - 1][j - a[i]]不为0,则表示拿了 i 这个物品,能把j的容量拿满,
则dp[i][j] = max(dp[i - 1][j], dp[i - 1][j - a[i]] + b[i]);
如果为0的话,则表示拿了 i 这个物品,无法将j的容量拿满。所以无需处理。
当a[i]>j的时候,无需处理。
同理,可以考虑从右向左遍历,使用一维数组来节约空间。
#include <bits/stdc++.h>
using namespace std;
int main() {
int n, v;
cin >> n >> v;
vector<int> a(n);
vector<int> b(n);
for (int i = 0; i < n; i++) {
cin >> a[i] >> b[i];
}
vector<int> dp(v + 1, 0);
vector<int> dp2(v + 1, 0);
for (int i = 0; i < n; i++)
for (int j = v; j >= 0; j--)
if (a[i] <= j)
dp[j] = max(dp[j], dp[j - a[i]] + b[i]);
cout << dp[v] << '\n';
for (int i = 0; i < n; i++) {
for (int j = v; j >= 0; j--) {
if (a[i] == j) {
dp2[j] = max(dp2[j], b[i]);
} else if (a[i] < j) {
if (dp2[j - a[i]] != 0) dp2[j] = max(dp2[j], dp2[j - a[i]] + b[i]);
}
}
}
cout << dp2[v] << '\n';
}
// 64 位输出请用 printf("%lld")



京公网安备 11010502036488号