[01分数规划]POJ2976 Dropping tests]经典二分题-01分数规划

题目链接

题目描述

给定N个元素,每个元素含有A[i],B[i],取其中N-K个元素得到:\frac{\sum a_i}{\sum b_i}\cdot 100,最大化这个值.

分析

使用二分答案:二分一个值V,使得\frac{\sum a_i}{\sum b_i} >= v,化简:\frac{\sum a_i}{\sum b_i} >= v \Rightarrow \sum a_i >= v\cdot \sum b_i \Rightarrow \sum a_i - v\cdot \sum b_i >= 0\Rightarrow \sum (a_i - v\cdot b_i) >= 0

那么可以在二分的check函数中选择前N-K个最大的(a_i - v\cdot b_i),检查是否大于等于0.

注意精度的处理。

#include 
#include 
#include 

using namespace std;

const int MAXN = 1001;

int N,K;
double
 A[MAXN],B[MAXN];

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

bool Check(double x)
{
	double Ssd[MAXN];
	for(int i = 1;i <= N;i++)
	{
		Ssd[i] = A[i]-x*B[i];
	}
	
	sort(Ssd+1,Ssd+1+N,cmp);
	
	double res = 0;
	for(int i = 1;i <= K;i++)
	{
		res += Ssd[i];
	}
	
	if(res >= 0)
	{
		return true;
	}
	else
	{
		return false;
	}
}

int main(void)
{
	cin >> N >> K;
        //K 是可能等于0的
	while(N != 0 || K != 0)
	{
		double l = 0;
		double r = 1;
		
		K = N-K;
		for(int i = 1;i <= N;i++)
		{
			cin >> A[i];
		}
		
		for(int i = 1;i <= N;i++)
		{
			cin >> B[i];
			
			r = max(r,A[i]/B[i]);
		}
		
		double ans = 0;
		while(r-l >= 1e-6)
		{
			double mid = (l+r)/2;
			
			if(Check(mid))
			{
				ans = mid;
				l = mid;
			}
			else
			{
				r = mid;
			}
			
		}
		printf("%.0lf\n",ans*100);
		cin >> N >> K;
	}
	return 0;
}

 

你可能感兴趣的:(算法,C++,二分)