1. 程式人生 > 實用技巧 >HDU6804:Contest of Rope Pulling——題解

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/+

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