问题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")