Dropping tests(POJ-2976)(Dinkelbach 算法)

Problem Description

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 .

Input

The input test file will contain multiple test cases, each containing exactly three lines. The first line contains two integers, 1 ≤ n ≤ 1000 and 0 ≤ k < n. The second line contains n integers indicating ai for all i. The third line contains n positive integers indicating bi for all i. It is guaranteed that 0 ≤ ai ≤ bi ≤ 1, 000, 000, 000. The end-of-file is marked by a test case with n = k = 0 and should not be processed.

Output

For each test case, write a single line with the highest cumulative average possible after dropping k of the given test scores. The average should be rounded to the nearest integer.

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

题意:多组数据,每组给出 n 个二元组 (a,b),扔掉 k 个二元组,使得剩下的 a 的和与 b 的和的比率最大

思路:

题目求的是:max(\sum\frac{a[i] * x[i]} { b[i] * x[i]}),其中 a[i]、b[i] 一一对应,x[i] 取 0、1,且 ∑x[i] = n - k

那么,令 r=\sum\frac{a[i]*x[i]}{b[i]*x[i]},则有:\sum a[i]*x[i]-\sum b[i]*x[i]*r=0

并有任意的:\sum a[i]*x[i]-\sum b[i]*x[i]*max(r)<=0

且当 \sum\frac{a[i]*x[i]}{b[i]*x[i]}=max(r) 时,\sum a[i]*x[i]-\sum b[i]*x[i]*max(r)=0 成立

可以看出,上述的模型是一个标准的 01分数规划模型,因此,直接对每个物品重新赋值为 a-x*b,排序后直接取前 n-k 大,然后利用 Dinkelbach 算法迭代求值即可

Source Program

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<string>
#include<cstring>
#include<cmath>
#include<ctime>
#include<algorithm>
#include<utility>
#include<stack>
#include<queue>
#include<vector>
#include<set>
#include<map>
#include<bitset>
#define PI acos(-1.0)
#define INF 0x3f3f3f3f
#define LL long long
#define Pair pair<int,int>
LL quickPow(LL a,LL b){ LL res=1; while(b){if(b&1)res*=a; a*=a; b>>=1;} return res; }
LL multMod(LL a,LL b,LL mod){ a%=mod; b%=mod; LL res=0; while(b){if(b&1)res=(res+a)%mod; a=(a<<=1)%mod; b>>=1; } return res%mod;}
LL quickMultPowMod(LL a, LL b,LL mod){ LL res=1,k=a; while(b){if((b&1))res=multMod(res,k,mod)%mod; k=multMod(k,k,mod)%mod; b>>=1;} return res%mod;}
LL quickPowMod(LL a,LL b,LL mod){ LL res=1; while(b){if(b&1)res=(a*res)%mod; a=(a*a)%mod; b>>=1; } return res; }
LL getInv(LL a,LL mod){ return quickPowMod(a,mod-2,mod); }
LL GCD(LL x,LL y){ return !y?x:GCD(y,x%y); }
LL LCM(LL x,LL y){ return x/GCD(x,y)*y; }
const double EPS = 1E-7;
const int MOD = 1000000000+7;
const int N = 1000+5;
const int dx[] = {0,0,-1,1,1,-1,1,1};
const int dy[] = {1,-1,0,0,-1,1,-1,1};
using namespace std;

double a[N], b[N];
double G[N];
int id[N];
bool cmp(int a, int b) {
    return G[a] > G[b];
}
int main() {
    int n,k;
    while(scanf("%d%d",&n,&k)!=EOF&&(n+k)){
        for(int i=1;i<=n;i++)
            scanf("%d",&a[i]);
        for(int i=1;i<=n;i++)
            scanf("%d",&b[i]);

        double left=0.5;//设置迭代初值
        double res=0;
        while(fabs(left-res)>EPS){
            res=left;
            for(int i=1;i<=n;i++){
                G[i]=a[i]-left*b[i];
                id[i]=i;
            }

            sort(id+1,id+n+1,cmp);//对标号按照G的大小排序

            double p=0,q=0;
            for(int i=1;i<=n-k;i++){//选择前n-k个
                p+=a[id[i]];
                q+=b[id[i]];
            }
            left=p/q;//更新比率
        }
        printf("%.0f\n",res*100);
    }
    return 0;
}
发布了1871 篇原创文章 · 获赞 702 · 访问量 194万+

猜你喜欢

转载自blog.csdn.net/u011815404/article/details/102652800
今日推荐