51Nod 1257 - 背包问题 V3(二分)

【题目描述】
在这里插入图片描述
【思路】
二分最大化平均值,设被选择的集合是 S S 那么对于某个单位价值 x x 我们去验证物品集合 S S 中的单位价值能否达到 x x 即验证下面的式子是否成立 i S p i w i > = x \sum_{i \in S} \frac{p_i}{w_i}>=x 移项后,等价于验证 i S ( p i x w i ) > = 0 \sum_{i \in S}(p_i-xw_i)>=0 是否成立,这样二分 x x 的值,然后每个物品就按照 p i x w i p_i-xw_i 排序然后贪心选择即可

#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;
}

猜你喜欢

转载自blog.csdn.net/xiao_k666/article/details/83753013