题目一般是这样的:有N个物品,每个物品重c[i],价值v[i],从中选K个,求

v [ i ] u s e [ i ] c [ i ] u s e [ i ]
最大
其中use[i]是0 或 1,表示选或不选这件物品

设最终答案为 r e s
即:

r e s = v [ i ] u s e [ i ] c [ i ] u s e [ i ]

化简一哈:
( r e s c [ i ] v [ i ] ) u s e [ i ] ) = 0

但是我们不知道res是多少,所以就设为 x 好啦~
设一大坨为 f ( x )
即:
f ( x ) = ( r e s c [ i ] v [ i ] ) u s e [ i ] )
x 不一样, f ( x ) 就不一样,并且当 x 越接近最终的 r e s f ( x ) 就越接近0对吧

于是我们就来猜 x ,运气好的话,刚好猜到一个 x 使得 f ( x ) = 0
But
However
Nevertheless
Whereas
Yet
我是一个喜欢靠实力的大帅比~而不喜欢靠运气0.0
所以我们发现 f ( x ) 是与 x 有关的,
我的这个 f ( x ) 是增函数, x 增大, f ( x ) 就增大
所以,
当我们得到 f ( x ) > 0 时,那就想要把 x 减小
反之, f ( x ) < 0 时,那就要把 x 弄大
所以,就是二分嘛

#include"iostream"
#include"algorithm"
#include"iomanip"
using namespace std;
const int maxn=1e5+5;
const double eps=1e-6;
int c[maxn],v[maxn];
struct AAA
{
    double f;
    int id;/*这个id是用来打印出来到底是选了哪K个*/
    bool operator<(const AAA &a)const
    {
        return f<a.f;
    }
};
AAA use[maxn];
int main()
{
    cout.setf(ios::fixed);
    int T;
    cin>>T;
    int N,K;
    while(T--)
    {
        cin>>N>>K;
        for(int i=0;i<N;i++)cin>>c[i]>>v[i];
        double L=-100,R=100;/*这里的边界要取得合适,上界要大于答案,下界要小于答案*/
        double x,fx;
        while(R-L>eps)
        {
            x=(L+R)/2.0;
            for(int i=0;i<N;i++)
            {
                use[i].f=1.0*x*c[i]-1.0*v[i];
                use[i].id=i+1;
            }
            sort(use,use+N);
            fx=0;
            for(int i=0;i<K;i++)fx+=use[i].f;/*因为要最大的嘛,就选出最大的K个*/
            if(fx>0)R=x;
            else L=x;
        }
        cout<<setprecision(2)<<x<<endl;

    }
}

第二种方法:

迭代法:

如果我们选的那K个物品的 a v e r a g e = v [ i ] c [ i ] 就是最终的res的话,那肯定是等于我们用这K个得到的average 来算的 f ( x )

这计算的与上一次计算的会越来越近,当他们的差小于一定值时,就认为相等,就是答案了


//迭代
#include"iostream"
#include"algorithm"
#include"iomanip"
using namespace std;
const int maxn=1e5+5;
const double eps=1e-6;
int c[maxn],v[maxn];
struct AAA
{
    double c,v,f;
    bool operator<(const AAA &a)const
    {
        return f<a.f;
    }
};
AAA use[maxn];
int main()
{
    cout.setf(ios::fixed);
    int T;
    cin>>T;
    int N,K;
    while(T--)
    {
        cin>>N>>K;
        for(int i=0;i<N;i++)cin>>use[i].c>>use[i].v;
        /*先随便猜一个答案*/
        double res=rand();
        double res_calc=res+1;/*这样是为了进循环*/
        while(fabs(res_calc-res)>eps)
        {
            res=res_calc;
            for(int i=0;i<N;i++)use[i].f=res*use[i].c-use[i].v;
            sort(use,use+N);
            double c_use=0,v_use=0;
            for(int i=0;i<K;i++)
            {
                c_use+=use[i].c;
                v_use+=use[i].v;
            }
            res_calc=1.0*v_use/c_use;/*res_calc就是根据res选的这K个计算而来的*/
        }
        cout<<setprecision(2)<<res<<endl;

    }
}