1. 程式人生 > >揹包問題 V3(二分)

揹包問題 V3(二分)

【題目描述】 在這裡插入圖片描述 【思路】 二分最大化平均值,設被選擇的集合是 SS 那麼對於某個單位價值 xx 我們去驗證物品集合 SS 中的單位價值能否達到 xx 即驗證下面的式子是否成立 iSpiwi>=x\sum_{i \in S} \frac{p_i}{w_i}>=x 移項後,等價於驗證 iS(pixwi)>=0\sum_{i \in S}(p_i-xw_i)>=0 是否成立,這樣二分 xx 的值,然後每個物品就按照 pixwip_i-xw_i

xwi 排序然後貪心選擇即可

#include<bits/stdc++.h>
#define max(a,b)(a>b?a:b)
using namespace std;
const int maxn=50005;
typedef long long ll;

ll gcd(ll a,ll b){ return b==0?a:gcd(b,a%b); }

int n,k;
ll up,down;
struct node{
	int p,w;
	double x;
	bool operator<(const node& e)const{
		return (p-x*w)>(e.p-e.x*e.w);
	}
}a[maxn];

bool check(double x){
	for(int i=0;i<n;++i) a[i].x=x;
	sort(a,a+n);
	ll sump=0,sumw=0;
	for(int i=0;i<k;++i){
		sump+=a[i].p;
		sumw+=a[i].w;
	}
	if(double(sump)/sumw>=x){
		up=sump/gcd(sump,sumw);
		down=sumw/gcd(sump,sumw);
		return true;
	}
	return false;
}

int main(){
	scanf("%d%d",&n,&k);
	double le=0,ri=0;
	for(int i=0;i<n;++i){
		scanf("%d%d",&a[i].w,&a[i].p);
		ri=max(ri,double(a[i].p)/a[i].w);
	}
	int cnt=100;
	while(cnt--){
		double mid=(le+ri)/2;
		if(check(mid)) le=mid;
		else ri=mid;
	}
	printf("%lld/%lld\n",up,down);
	return 0;
}