POJ 2976 Dropping tests(贪心+二分)

Description
n场考试中分别答对ai题,总题数分别为bi,允许去掉k场考试,求能达到的最高准确率
Input
多组用例,每组用例第一行为两个整数n和k分别表示考试次数和可去考试次数,第二行为每次考试答对的题数,第三行为每次考试的总题数,以n=k=0结束输入
Output
对于每组用例,输出去掉k次考试后的最高准确率
Sample Input
3 1
5 0 2
5 1 6
4 2
1 2 7 9
5 6 7 9
0 0
Sample Output
83
100
Solution
需要确定一个贪心策略,每次贪心地去掉那些对正确率贡献小的考试。如何确定某个考试[ai, bi]对总体准确率x的贡献呢?ai / bi肯定是不行的,不然例子里的[0,1]会首当其冲被刷掉。在当前准确率为x的情况下,这场考试“额外”对的题目数量是ai – x * bi,当然这个值有正有负,恰好可以作为“贡献度”的测量。于是利用这个给考试排个降序,后k个刷掉就行了
Code

#include<cstdio>
#include<cstring>
#include<cmath>
#include<iostream>
#include<algorithm>
#include<functional>
using namespace std;
#define maxn 10005
#define eps 1e-4
int a[maxn],b[maxn];
int n,k;
double C(double x)
{
    double ans=0,d[maxn];
    for(int i=0;i<n;i++)
    {
        ans+=1.0*100*a[i]-1.0*x*b[i];//额外对的题 
        d[i]=1.0*100*a[i]-1.0*x*b[i];
    }
    sort(d,d+n);//对每次考试的贡献排序 
    for(int i=0;i<k;i++)//减去贡献最少的 
        ans-=d[i];
    return ans>-eps;
}
int main()
{
    while(scanf("%d%d",&n,&k)&&(n||k))
    {
        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=100,ans=-1;//x是百分比,所以l=0,r=100 
        while(r-l>eps)
        {
            double mid=(l+r)/2;
            if(C(mid))
                l=ans=mid;
            else
                r=mid;
        }
        printf("%.lf\n",ans);
    }
    return 0;
}

你可能感兴趣的:(POJ 2976 Dropping tests(贪心+二分))