最大化平均值(二分搜索)

版权声明:希望能帮到弱校的ACMer成长,因为自己是弱校菜鸡~~~~ https://blog.csdn.net/Mr__Charles/article/details/82875808

题目原文

  有n个物品的重量和价值分别是w[i]和v[i]。从中选出k个物品使得单位重量的价值最大。数据范围

  1<=k<=n<=10^4

  1<=w[i],v[i]<=10^6

解题思路

  定义C(x):可以选择使得单位重量的价值不小于x。

  原问题就变成了求满足C(x)的最大的x。

  假设我们选择的物品的集合是S,那么它们单位重量的价值是

  ∑v[i]/∑w[i]

  ∑v[i]/∑v[i]>=x变形得∑(v[i]-x*w[i])>=0.

  因此可以对v[i]x*w[i]的值进行排序贪心的进行选取

  因此就变成了C(x)=((v[i]-x*w[i])从大到小排列中前k个的和不小于0)。

  每次判断的时间复杂度为O(nlogn)。

代码

#include<cstdio>
#include<iostream>
#include<algorithm>
using namespace std;
const int MAXN = 1e4;
const int INF = 0x3f3f3f3f;
int n,k;
double m[MAXN+5];

struct goods{
	int w,v;
}g[MAXN+5];

bool cmp(double a,double b){
	return a > b;
}

bool judge(double x){
	for(int i = 0; i < n; ++i)
	    m[i] = g[i].v - g[i].w * x;
	sort(m,m+n,cmp);
	double sum = 0;
	for(int i = 0; i < k; ++i)
		sum += m[i];
	return sum >= 0;
}

void solve(){
	double L = 0,R = INF;
	for(int i = 0; i < 100;++i){
		double mid = (L + R)/2;
		if(judge(mid)) L = mid;
		else R = mid;
	}
	printf("%.2lf\n",R);
}

int main(){
	while(~scanf("%d%d",&n,&k)){
		for(int i = 0; i < n; ++i)
			scanf("%d%d",&g[i].w,&g[i].v);
		solve();
	}
	return 0;
}

猜你喜欢

转载自blog.csdn.net/Mr__Charles/article/details/82875808
今日推荐