2020 hdu多校4 1003 Contest of Rope Pulling(01揹包+隨機化)
阿新 • • 發佈:2020-07-31
題意
\(T\)組資料,有\(n\),\(m\)代表每個班級的人數,每個人有兩種屬性\(w_i\)(力量值),\(v_i\)(魅力值),問你從兩班中選擇兩個子集(可為空),使得兩個子集的力量值和相等,求選出來的所有人的魅力值和的最大值
解法
可以將兩組人合併為一組,這裡只需要將第二組的力量值改成負數就行。之後我們在dp陣列上進行01揹包,\(dp[0]\),就是答案。不過因為dp的時候下標可能為負數,所以需要加上一個基值代表\(0\)。
因為我們所求的是恰好揹包裝到\(0\)的值,所以需要將整個dp陣列初始化為\(-INF\), 並且每次dp的時候確保\(dp[j - w[i]]\)不為\(-INF\)
程式碼
#include <bits/stdc++.h> using namespace std; typedef long long ll; const ll N = 3e3 + 7; const ll M = 1e5 + 7; const ll INF = 1e18; inline int read() { int x = 0, f = 1; char ch = getchar(); while (ch < '0' || ch > '9') { if (ch == '-') f = -1; ch = getchar(); } while (ch >= '0' && ch <= '9') { x = x * 10 + ch - '0'; ch = getchar(); } return x * f; } int t; int n, m; struct node{ ll w, v; }; node a[N]; ll dp[M]; ll getdp(int n) { fill(dp, dp + M, -INF); dp[50000] = 0; for (int i = 1; i <= n;i++) { if(a[i].w >= 0) { for (int j = 1e5; j >= a[i].w;j--) { if(dp[j - a[i].w] != -INF) dp[j] = max(dp[j], dp[j - a[i].w] + a[i].v); } } else { int lim = 1e5 + a[i].w; for (int j = 0; j <= lim; j++) { if (dp[j - a[i].w] != -INF) dp[j] = max(dp[j], dp[j - a[i].w] + a[i].v); } } } return dp[50000]; } int main() { srand(time(0)); t = read(); //scanf("%d", &t); while(t--) { n = read(), m = read(); //scanf("%d %d", &n, &m); for (int i = 1; i <= n + m;i++) { //scanf("%lld %lld", &a[i].w, &a[i].v); a[i].w = read(), a[i].v = read(); if(i > n) a[i].w = -a[i].w; } random_shuffle(a + 1, a + n + m + 1); ll ans = 0; ans = getdp(n + m); printf("%lld\n", ans); } return 0; }