最大化平均值

和最大化最小值类似,最大化平均值也可以通过二分法求得。

比如下面这个经典的问题: 
有n个物品的重量和价值分别是wi和vi,从中选出k个物品使得单位重量价值最大。

样例输入:

3 2
2 2
5 3
2 1

样例输出:

0.75

分析:

一般先想到的是将每个物品的单位重量价值算出来,然后排个序,从大到小贪心进行选择,可惜这样是不对的,这样不能保证最后一定是最大平均值,直接用贪心对于这类要涉及多个因素比如求最大平均值的问题就显得不那么正确了。

那么我们这样分析这个问题: 
令C(x)为可以选择使得单位重量的价值不小于x。 
这样就可以用二分法来解决,不断二分x进行判断,取最大。

我们继续分析:

 ∑vi / ∑wi 这个式子是我们需要求的单位重量的价值。 
 i∈s   i∈s

那么就求是否满足:

 ∑vi / ∑wi >= x
 i∈s   i∈s

转换一下得到:

∑(vi - x*wi) >= 0
i∈s 

判断这个式子是否成立即可。这下就可以用一个数组来保存vi - x * wi 的值,并进行排序,从大到小贪心地进行选择求和,如果求和的值大于0,那么此时 的x就是成立的。

#include<stdio.h>
#include<algorithm>
using namespace std;
#define INF 0x3f3f3f3f
bool cmp(double a,double b)
 {
     return a>b;
 }
 int n,k;
 double y[20010];
 int w[20010],v[20010];
bool C(double x)
{
    for(int i = 0 ; i < n ; i++)
    {
        y[i]=v[i]-x*w[i];
    }
    sort(y,y+n,cmp);
    double sum=0;
    for(int i = 0 ; i < k ; i++)
        sum+=y[i];
        if(sum>=0)
            return true;///x太小
            return false///x太大
}
int main()
{
    scanf("%d%d",&n,&k);
    for(int i = 0 ; i  < n ; i++)
        scanf("%d%d",&w[i],&v[i]);
    double st = 0,en = INF;
    for(int i=1;i<=100;i++)///精度
    {
        double mid = (st+en)/2;
        if(C(mid))
            st=mid;
        else
            en=mid;
    }
    printf("%.2f\n",en);

}
View Code

 

posted @ 2018-04-23 21:19  shuai_hui  阅读(458)  评论(1编辑  收藏  举报