清题笔记2020多校4 1004 Contest of Rope Pulling(01背包加随机化)

题目描述

拉绳,也叫拔河,是一种经典的游戏。张三组织了一班和二班的拉绳比赛。
一班有学生,二班有学生。张三需要从两个班中选出一部分学生,让一班与二班的学生竞争。
它也被允许不从一个班里挑选学生或选择所有的学生。
为了公平竞争,两队的总实力必须相等。为了让比赛更漂亮,张三想选择这样一组学生,让所有参赛者的总美丽价值最大化。
请帮助她确定最佳的总美容价值。

输入

输入的第一行给出测试用例的数量T(1≤T≤30)。

测试案例如下。

对于每个测试用例,第一行包含两个整数n,m(1≤n,m≤1000),代表1班和2班的学生人数。 接下来是(n+m)行,描述学生。ithline包含两个整数wi,vi(1≤wi≤1000,−109≤vi≤109),代表ITH学生的力量和美丽价值。第一批学生来自1班,其他学生来自2班。
所有测试用例中的(n+m)之和不超过104。

输出

对于每个测试用例,打印一条带有整数的行,表示最佳的总美感值。

样例输入

2
3 4
4 7
3 8
2 2
14
5 8
13
4 4
12
1000 -10000
200 3000
800 5000
# 样例输出
30
0

思路:

01背包加随机化,题意可以转换为有质量为正的和负的物品,求和为0时的最大价值。由于数组不能开太大,按顺序全是正的或负的会超范围,把数组随机化.定一个base作为初始值,开始背包问题。

代码:

#include<bits/stdc++.h>
#define ll long long
using namespace std;
const int mod=1e9+7;
const ll INF=1e15;
const int maxn=2e3+10;
const int maxdp=1e5+10;
const int base=5e4;
const int lim=1e5;
struct node{
	int w,v;
}a[maxn];
ll w[maxn],v[maxn];
ll temp[maxdp];
ll dp[maxdp];
void init(){
    fill(dp,dp+maxdp,-INF);
    fill(temp,temp+maxdp,-INF);
    dp[base]=0;
    temp[base]=0;
}
int main () {
    int T;
    scanf("%d",&T);
    while(T--){
        int n,m;
        scanf("%d%d",&n,&m);
        init();
        for(int i=1;i<=n+m;i++){
            scanf("%d%d",&a[i].w,&a[i].v);
            if(i>n){
                a[i].w=-a[i].w;
            }
        }
        random_shuffle(a+1,a+1+n+m);
        for(int i=1;i<=n+m;i++){
            for(int j=min(lim,(int)lim+(int)a[i].w);j-a[i].w>=0;j--){
                if(dp[j-a[i].w]!=-INF){
                    temp[j]=max(dp[j],dp[j-a[i].w]+a[i].v);
                }
            }
            for(int j=0;j<=maxdp-1;j++){
                dp[j]=temp[j];
            }
        }
        printf("%lld\n",dp[base]);
    }
}

猜你喜欢

转载自blog.csdn.net/Nefeertari/article/details/107727646