POJ - 2976 最大化平均值....

/**
链接:http://poj.org/problem?id=2976

题意:给定两组序列a b 去掉k个二元组(同一个i对应的a b) 使得a的总和除以b的总和最大;

分析: 对于任意二元组 a b 都存在 x = a / b + c ; c为待定数(表示二元组值与平均值的差值) 

寻找最合适的 x  因此可以选择0作为差值点进行规划

化简后得到 -------->

b * x = a + c----> a - b * x = c ; 差值对于倍数的放大是不影响的(同增或同减); 

因此可通过二分枚举x找到差值  找到差值后  需要最大化平均数 则需看差值和 和 0的大小关系 
>=0  x 过小  ;  <0  x 过大 
那么 将这种化简目标表达式的方法也称之为0/1分数规划; 说白了 一般通过二分向着目标答案靠近;
可直接将目标进行化简为 a/b>=x ---> a-b*x>=0; 那么a-b*x就是所谓的构造数组;

*/

#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cmath>
#define ll long long
using namespace std;

const int maxn=1e3+7;
const double eps=1e-6;

int n,k,a[maxn],b[maxn];

bool judge(double x){
	double tmp[maxn];
	for(int i=0;i<n;i++) tmp[i]=a[i]-x*b[i];
	sort(tmp,tmp+n);
	double sum=0;
	for(int i=k;i<n;i++) sum+=tmp[i];
    return  sum>=0.0;
}

int main (){
	while(~scanf("%d %d",&n,&k)){
		if(n==0&&k==0) break;
		for(int i=0;i<n;i++) scanf("%d",&a[i]);
		for(int i=0;i<n;i++) scanf("%d",&b[i]);
		double l=0,r=1.0;
		while(fabs(r-l)>eps){
			double mid=(l+r)/2;
			if(judge(mid)) l=mid;
			else r=mid;
		}
		int ans=(int)(l*100+0.50);
		printf("%d\n",ans);
	}
	return 0;
}

猜你喜欢

转载自blog.csdn.net/hypHuangYanPing/article/details/81105062
今日推荐