题目描述

wyh学长现在手里有n个物品,这n个物品的重量和价值都告诉你,然后现在让你从中选取k个,问你在所有可能选取的方案中,最大的单位价值为多少(单位价值为选取的k个物品的总价值和总重量的比值)

输入描述:

输入第一行一个整数T(1<=T<=10)
接下来有T组测试数据,对于每组测试数据,第一行输入两个数n和k(1<=k<=n<=100000)
接下来有n行,每行两个是a和b,代表这个物品的重量和价值

输出描述:

对于每组测试数据,输出对应答案,结果保留两位小数


0/1 分数规划

本题可以抽象成给定对整数,从中选出若干对,使选出的数对的之和
之和的商最大。

不妨猜测一个值,然后考虑这样一个问题,是否存在一种方案使得成立。

如果存在这样的方案使得成立,那么变形得进一步可知: 成立。也就是说,比我们求的最大值要小。

如果对于任意一种情况,都有成立,那么变形之后可以得到成立。也就是说,比我们求的最大值要大。

这与“二分答案”的情形非常相似,即本题的答案满足单调性。虽然最终的答案是未知的,但是如果我
一个值,就能通过判定是否存在一组解满足来确定应该变得更大还是更小。也就是说,解的存在具有单调性。

如何判定“是否存在一组解满足呢?显然,我们只需要判定这个式子的最大值是否为非负的。这个判定问题显然比原问题要简单得多,因为;可以直接求出。这就等价于从n个数里选出若干个,使它们的和最大。

综上所述,我们可以二分答案来求解本题。

完整代码

#include<bits/stdc++.h>
using namespace std;
pair<double,double> a[100500];
int n,k;
double c[100500];
bool check(double x){
    for(int i=1;i<=n;++i){
        c[i]=a[i].second-x*a[i].first;
    }
    sort(c+1,c+1+n);
    double sum=0;
    for(int i=n;i>n-k;--i){
        sum+=c[i];
    }
    //cout<<x<<" "<<sum<<endl;
    return sum>=0;
}
int main(){
    int T;
    scanf("%d",&T);
    while(T--){
        scanf("%d%d",&n,&k);
        for(int i=1;i<=n;++i)scanf("%lf%lf",&a[i].first,&a[i].second);
        double l=0,r=1e9;
        double ans;
        for(int cnt=0;cnt<100;++cnt){
            double mid=(l+r)/2;
            if(check(mid))ans=mid,l=mid;
            else r=mid;
        }
        printf("%.2f\n",ans);
    }
}