題目來源
https://cometoj.com/contest/81/problem/I
題面描述
題意
揹包:給你,每個物品有自己的價值和價格,問m塊錢能買的東西總價值最大。
這裏在揹包的基礎上加了個查詢,每個查詢可以改變第個物品的價值和價格,重新求一遍最大價值。()
思路
如果暴力揹包,算一下複雜度顯然會,嘗試一下吧,看看效果
其實不難發現,我們每次修改只有一個物品的信息,而且我們二維揹包有記錄二維狀態,我們可以正反做一次揹包,令代表到的物品,用了容量的最大價值,代表到的物品,用了容量的最大價值。
比如修改的物品是,而我們已知的有和這些物品的值,枚舉容量求最大值即可。(注意)
詳見代碼:
#include <bits/stdc++.h>
using namespace std;
const int N = 2e3 + 10;
#define ll long long
ll dp1[N][N], dp2[N][N], now[N], lat[N], a[N], b[N];
signed main() {
ios::sync_with_stdio(false);
cin.tie(0);
int n, m, t;
cin >> n >> m >> t;
for (int i = 1; i <= n; i++) {
cin >> a[i] >> b[i];
}
for (int i = 1; i <= n; i++) { //正着dp
for (int j = 0; j <= m; j++) {
if (j >= a[i]) {
dp1[i][j] = max(dp1[i - 1][j], dp1[i - 1][j - a[i]] + b[i]);
}
dp1[i][j] = max(dp1[i - 1][j], dp1[i][j]);
}
}
for (int i = n; i >= 1; i--) { //反着dp
for (int j = 0; j <= m; j++) {
if (j >= a[i]) {
dp2[i][j] = max(dp2[i + 1][j], dp2[i + 1][j - a[i]] + b[i]);
}
dp2[i][j] = max(dp2[i + 1][j], dp2[i][j]);
}
}
for (int i = 0; i < t; i++) {
ll x, c, d;
cin >> x >> c >> d;
memset(now, 0, sizeof(now));
memset(lat, 0, sizeof(lat));
for (int j = 0; j <= m; j++) { // 1 到 x-1個物品用容量爲j的最大價值
now[j] = dp1[x - 1][j];
}
for (int j = m; j >= c; j--) { // x物品修改後用容量爲j的最大價值,對後面狀態的影響
now[j] = max(now[j], now[j - c] + d);
}
for (int j = 1; j <= m; j++) { // x物品修改後用容量爲j的最大價值
now[j] = max(now[j], now[j - 1]);
}
for (int j = 1; j <= m; j++) { // x+1 到 n 個物品用容量爲j的最大價值
lat[j] = max(lat[j - 1], dp2[x + 1][j]);
}
ll ans = 0;
for (int j = 0; j <= m; j++) { //枚舉容量 求最大值
ans = max(ans, lat[m - j] + now[j]);
}
cout << ans << endl;
}
return 0;
}