2020 Multi-University Training Contest 4 1012 Last Problem(01背包)

题目

  http://acm.hdu.edu.cn/showproblem.php?pid=6804

题意

  分别给出 n,m 对数(w,v),在 n 对 和 m 对中分别取出若干对使得 w 的和相等,在这个前提下使所有的 v 之和最大,问 v 最大值为多少。

题解

  首先看到这个题意,第一时间想到对 n 和 m 分别跑一遍01背包最后在枚举 w 的值取出最大的那个,可是这样的话我们会发现跑一遍01背包就需要 1e9,时间上过不去。所以我们先将 m 对数的 w 取反,然后将 n 和 m 对数放一起同时跑,答案就是 dp[0] 了。为了将时间缩小我们将 n 和 m 对数放在一起随机打乱,使得数值能够在 0 附近震荡,在这种情况下当绝对数很大时能恢复到 0 的概率很小,所以就能将原来 1e6 的 dp 数组减小,只在 1e5 的范围内更新就好。

#include <bits/stdc++.h>
// #include <iostream>
// #include <cstring>
// #include <string>
// #include <algorithm>
// #include <cmath>
// #include <cstdio>
// #include <queue>
// #include <stack>
// #include <map>
// #include <bitset>
// #include <set>
// #include <vector>
// #include <iomanip>
#define ll long long
#define ull unsigned long long
#define met(a, b) memset(a, b, sizeof(a))
#define rep(i, a, b) for(int i = a; i <= b; ++i)
#define bep(i, a, b) for(int i = a; i >= b; --i)
#define lowbit(x) (x&(-x))
#define MID (l + r) / 2
#define ls pos*2
#define rs pos*2+1
#define pb push_back
#define ios() ios::sync_with_stdio(0), cin.tie(0), cout.tie(0)

using namespace std;

const int maxn = 1e6 + 1010;
const int inf = 0x3f3f3f3f;
const ll INF = 0x3f3f3f3f3f3f3f3f;
const ll mod = 1e9 + 7;
const double eps = 1e-6;
const double PI = acos(-1);

struct node {
    ll w, v;
}arr[maxn];

ll dp[maxn], tail;

int main() {
    srand(time(0));
    int T;
    scanf("%d", &T);
    while(T--) {
        rep(i, 0, maxn - 1) dp[i] = -INF;
        int n, m;
        scanf("%d%d", &n, &m);
        tail = 0;
        rep(i, 1, n) {
            tail++;
            scanf("%lld%lld", &arr[tail].w, &arr[tail].v);
        }
        rep(i, 1, m) {
            tail++;
            scanf("%lld%lld", &arr[tail].w, &arr[tail].v);
            arr[tail].w = -arr[tail].w;
        }
        random_shuffle(arr + 1, arr + 1 + tail);
        dp[100000] = 0;
        rep(i, 1, tail) {
            if(arr[i].w > 0) {
                bep(j, 200000, arr[i].w) {
                    dp[j] = max(dp[j], dp[j - arr[i].w] + arr[i].v);
                }
            }
            if(arr[i].w < 0) {
                rep(j, 0, 200000 + arr[i].w) {
                    dp[j] = max(dp[j], dp[j - arr[i].w] + arr[i].v);
                }
            }
        }
        printf("%lld
", dp[100000]);
    }
    return 0;
}
原文地址:https://www.cnblogs.com/Ruby-Z/p/13414900.html