中國計量大學現代科技學院第四屆“中競杯”程序設計校賽 01揹包 狀態存儲

題目來源

https://cometoj.com/contest/81/problem/I

題面描述

在這裏插入圖片描述
在這裏插入圖片描述

題意

0101揹包:給你nmn個物品m塊錢,每個物品有自己的價值bib_i和價格aia_i,問m塊錢能買的東西總價值最大。

這裏在0101揹包的基礎上加了tt個查詢,每個查詢可以改變第xx個物品的價值和價格,重新求一遍最大價值。(n,m,ai2e3,t3e3,bi1e9n,m,a_i \leq 2e3 ,t \leq 3e3,b_i \leq 1e9

思路

如果暴力0101揹包,算一下複雜度n2t=12e9n^2*t=12e9顯然會tletle,嘗試一下吧,看看效果

在這裏插入圖片描述
其實不難發現,我們每次修改只有一個物品的信息,而且我們二維0101揹包有記錄二維狀態,我們可以正反做一次0101揹包,令dp1[i][j]dp1[i][j]代表11ii的物品,用了jj容量的最大價值,dp2[i][j]dp2[i][j]代表iinn的物品,用了jj容量的最大價值。

比如修改的物品是xx,而我們已知的有1x11到x-1x+1nx+1到n這些物品的dpdp值,枚舉容量求最大值即可。(注意longlonglong long)

詳見代碼:

#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;
}
發佈了305 篇原創文章 · 獲贊 222 · 訪問量 13萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章