POJ 2976 Dropping tests 二分,最大化平均值

一、题目大意

你经过了n次测试,第i次测试共有b[i]道题目,其中答对了a[i]道题目,对于1<=i<=n我们从中去掉k个,使得剩余的值中a[i]的和除以b[i]的和最大。

二、思路

我们对平均值进行二分,判断每个平均值mid是否能够达到,如果能够达到就放大,达不到就缩小,输出最后一个满足条件的平均值即可。

判断平均值可达性的过程需要看下这三个不等式

(a1+a2+a3+a4)/(b1+b2+b3+b4)>=mid
a1 + a2 + a3 + a4 >= mid * b1 + mid * b2 + mid * b3 + mid * b4
(a1 - mid * b1) + (a2 -  mid * b2) + (a3 - mid * b3) + (a4 - mid * b4) >=  0

那么不难看出,我们对于每一个mid,计算a[i]-b[i]*mid,然后把计算的结果排个序,找出最大的n-k个,求和与0比较,即可判断mid是否可行。

三、代码

#include 
#include 
using namespace std;
double eps = 0.0001;
int n, k, a[1007], b[1007];
double express[1007];
void input()
{
    for (int i = 0; i < n; i++)
    {
        scanf("%d", &a[i]);
    }
    for (int i = 0; i < n; i++)
    {
        scanf("%d", &b[i]);
    }
}
bool compare(const double &a, const double &b)
{
    return a > b;
}
bool judge(double mid)
{
    for (int i = 0; i < n; i++)
    {
        // 最大化平均值,
        //(a1+a2+a3+a4)/(b1+b2+b3+b4)>=mid
        // a1 + a2 + a3 + a4 >= mid * b1 + mid * b2 + mid * b3 + mid * b4
        //(a1 - mid * b1) + (a2 -  mid * b2) + (a3 - mid * b3) + (a4 - mid * b4) >=  0
        express[i] = a[i] * 1.0;
        express[i] -= (mid * 1.0 * b[i]);
    }
    sort(express, express + n, compare);
    double sum = 0.0;
    for (int i = 0; i < (n - k); i++)
    {
        sum += express[i];
    }
    return sum >= 0.000;
}
void binarySearch()
{
    double left = 0.00, right = 1.0001;
    while (left + eps < right)
    {
        double mid = (left + right) / 2;
        if (judge(mid))
        {
            left = mid;
        }
        else
        {
            right = mid;
        }
    }
    left *= 100;
    printf("%.0f\n", left);
}
int main()
{
    while (~scanf("%d%d", &n, &k))
    {
        if (n == 0 && k == 0)
        {
            break;
        }
        input();
        binarySearch();
    }
    return 0;
}

你可能感兴趣的:(算法)