1. 程式人生 > 實用技巧 >2020 hdu多校4 1003 Contest of Rope Pulling(01揹包+隨機化)

2020 hdu多校4 1003 Contest of Rope Pulling(01揹包+隨機化)

題意

\(T\)組資料,有\(n\)\(m\)代表每個班級的人數,每個人有兩種屬性\(w_i\)(力量值),\(v_i\)(魅力值),問你從兩班中選擇兩個子集(可為空),使得兩個子集的力量值和相等,求選出來的所有人的魅力值和的最大值

解法

可以將兩組人合併為一組,這裡只需要將第二組的力量值改成負數就行。之後我們在dp陣列上進行01揹包,\(dp[0]\),就是答案。不過因為dp的時候下標可能為負數,所以需要加上一個基值代表\(0\)
因為我們所求的是恰好揹包裝到\(0\)的值,所以需要將整個dp陣列初始化為\(-INF\), 並且每次dp的時候確保\(dp[j - w[i]]\)不為\(-INF\)

(這麼做可以確保dp到j的時候前面都是確實加過其他人的魅力值,而不是空的)。另外得注意一下\(w[i]\)為負數時dp的範圍與方向,這隻要確保\(dp[j - w[i]]\)值的更新在\(dp[j]\)之後就行,範圍只要不超過陣列的範圍就行。

程式碼

#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;
}