hdu 6804【2020杭电多校赛第四场1003】【负值01背包】【random_shuffle】

Source

hdu 6804 Contest of Rope Pulling

Solution

有两个班级,一班有n个人,二班有m个人,每个人都有力气值和美丽值,从两个班分别选出任意个人,要让他们的力气之和相同(可以全选也可以不选),并使它们的美丽值最大。

实际上我们可以把题目转化成01背包问题:n+m个物品,把力气作为cost,把美丽值作为value,一班的cost做负贡献,二班的cost做正贡献,最后取dp[0]即可。

但是根据题目给出的数据范围,dp[x]的x范围最大为-106~106。我看了官方题解之后,才知道,可以随机打乱数组,使得范围大幅度缩小。这里使用了random_shuffle函数。最后锁定在-5*104~5*104附近。因为存在负值,所以把背包整体往右挪一段。从dp[-50000]~dp[50000]变成dp[0]~dp[105],最后取中值dp[50000]。

dp要开long long,初始化要非常小才够用。背包那一段不能用max,会TLE
在这里插入图片描述

Code

/*
 * @Author: SolitaryOrz 
 * @Date: 2020-07-31 14:31:08 
 * @Last Modified by: SolitaryOrz
 * @Last Modified time: 2020-07-31 19:37:38
 */
#include
using namespace std;
typedef long long ll;
const int maxn = 2020;
const int mod = 1e9+7;
const ll inf = 0x3f3f3f3f3f3f3f3f;

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

ll dp[100010];

void init() {
    for(int i=0;i<=100000;i++) {
        dp[i] = -inf;
    }
} 

void ZeroOnePack(int cost, int weight) {
    if(cost >= 0) {
        for(int i=100000;i>=cost;i--) {
            if(dp[i-cost]+weight > dp[i]) 
                dp[i] = dp[i-cost]+weight;
        }
    }
    else {
        for(int i=0;i<=100000+cost;i++) {
            if(dp[i-cost]+weight > dp[i]) 
                dp[i] = dp[i-cost]+weight;
        }
    }
}

int main() {
    int t;
    scanf("%d",&t);
    while(t--) {
        int n,m;
        scanf("%d%d",&n,&m);
        for(int i=0;i<n;i++) {
            scanf("%d%d",&arr[i].w,&arr[i].v);
            arr[i].w = -arr[i].w;
        }
        for(int i=n;i<n+m;i++) {
            scanf("%d%d",&arr[i].w,&arr[i].v);
        }
        random_shuffle(arr,arr+n+m);
        init();
        dp[50000] = 0;
        for(int i=0;i<n+m;i++) {
            ZeroOnePack(arr[i].w,arr[i].v);
        }
        printf("%lld\n",dp[50000]);
    }
}

你可能感兴趣的:(DP,HDU,01背包,2020杭电多校赛,hdu6804)