1. 程式人生 > >『POJ 2976』Dropping tests (01分數規劃)

『POJ 2976』Dropping tests (01分數規劃)

code cmp pro take rip gist become i++ determine

題目鏈接

Descrip

In a certain course, you take n tests. If you get ai out of bi questions correct on test i, your cumulative average is defined to be

技術分享圖片.

Given your test scores and a positive integer k, determine how high you can make your cumulative average if you are allowed to drop any k of your test scores.

Suppose you take 3 tests with scores of 5/5, 0/1, and 2/6. Without dropping any tests, your cumulative average is 技術分享圖片. However, if you drop the third test, your cumulative average becomes 技術分享圖片.



題目描述

現在有n個物品,每個物品都有兩個價值,一個價值為\(a\),一個價值為\(b\),(保證\(a_i\leq b_i\))現在最多可以有k個物品不選,請問能夠使選擇的物品的\(100*\frac{\sum a_i}{\sum b_i}\)

最大是多少?



解題思路

顯然是一道01分數規劃的題目,因為題目中說明了\(a_i\leq b_i\),那最終的取值就只能是\(0\)\(100\)之間,所以我們把那個100提出來,答案的區間就變成了\([0,1]\),所以,我們可以二分答案去驗證可行性。

數學證明

假設\(\frac{\sum a_i}{\sum b_i}\ge x\),那就有\(\sum a_i\ge x*\sum b_i\),即\(\sum a_i-x*\sum b_i\ge0\),我們只要處理出每個物品\(i\)的另一個價值\(a_i-x*b_i\),然後從大到小排序,計算前\(n-k\)個物品的價值的和,是否大於等於0就好了。

一點小細節

註意一下eps的設置就好了。



代碼

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
using namespace std;
const int maxn=1050;
const double eps=1e-5;
int n,k;
int a[maxn],b[maxn];
double tmp[maxn];
inline bool cmp(double x,double y){
    return x>y;
}
inline bool check(double x){
    for(register int i=1;i<=n;i++){
        tmp[i]=(double)a[i]-1.0*b[i]*x;
    }
    sort(tmp+1,tmp+1+n,cmp);
    double ans=0;
    for(register int i=1;i<=n-k;i++)ans+=tmp[i];
    return ans>=0;
}
int main(){
    while(~scanf("%d%d",&n,&k)){
        if(n+k==0)return 0;
        for(register int i=1;i<=n;i++)scanf("%d",&a[i]);
        for(register int i=1;i<=n;i++)scanf("%d",&b[i]);
        register double l=0.0,r=1.0;
        while(r-l>eps){
            register double m=(l+r)/2;
            if(check(m))l=m;
            else r=m;
        }
        l*=100;
        printf("%.0lf\n",l);
    }
}

『POJ 2976』Dropping tests (01分數規劃)