HDU6804:Contest of Rope Pulling——题解

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

两班各选几人参加比赛,每个人都有体重和魅力值,要求在两边体重相等的情况下魅力值最大。

看起来是经典背包题,但是由于体重的和最大可能达到 $10^6$ ,所以复杂度爆表。

于是……为什么最近的几场比赛都和随机有关系?

简单看了题解,直接说结论与感性证明(理性证明我也看了,不是很难理解,可以自己去看看):

将所有选手随机排列然后依次算背包,背包的容量限定在范围 $[-A,A]$ 中即可,而这个 $A$ 足够大即可(事实上,题解证明这个 $A$ 的大小为 $ O(\sqrt{n+m})$ 即可)

感性证明:我们只考虑最优解的人的集合,然后在随机的过程中也会将这个集合进行打乱从而随机被加入背包计算。而感性想一下当人的体重为最大值1000的时候可能会出现在相加的过程中体重和的最大值。而在这种情况下这个峰值仍然也不会很大。

#include<bits/stdc++.h>
#define fi first
#define se second
using namespace std;
typedef long long ll;
const int N=2e3+5;
const int A=1e5;
const ll INF=1e18;
inline int read(){
    int X=0,w=0;char ch=0;
    while(!isdigit(ch)){w|=ch=='-';ch=getchar();}
    while(isdigit(ch))X=(X<<3)+(X<<1)+(ch^48),ch=getchar();
    return w?-X:X;
}
struct item{
    int v;
    ll w;
}a[N];
int n,m;
ll f[2][A*2+5];
void init(){
    for(int j=0;j<=2*A;j++){
        f[0][j]=f[1][j]=-INF;
    }
    f[0][A]=0;
}
int main(){
    srand(time(0));
    int T=read();
    while(T--){
        n=read(),m=read();
        init();
        for(int i=1;i<=n;i++){
            a[i].v=read();a[i].w=read();
        }
        for(int i=n+1;i<=n+m;i++){
            a[i].v=-read();a[i].w=read();
        }
        n+=m;
        int lim=sqrt(n)*1000*2;
        int L=-lim,R=lim,pre=0;
        random_shuffle(a+1,a+n+1);
        for(int i=1;i<=n;i++){
            int nxt=pre^1;
            for(int j=L;j<=R;j++){
                f[nxt][j+a[i].v+A]=max(f[pre][j+a[i].v+A],f[pre][j+A]+a[i].w);    
            }
            pre=nxt;
        }
        printf("%lld\n",f[pre][A]);
    }
    return 0;
}

+++++++++++++++++++++++++++++++++++++++++++

 +本文作者:luyouqi233。               +

 +欢迎访问我的博客:http://www.cnblogs.com/luyouqi233/+

+++++++++++++++++++++++++++++++++++++++++++

posted @ 2020-07-31 20:18  luyouqi233  阅读(332)  评论(0编辑  收藏  举报