首页 > 代码库 > nyoj914(二分搜索+贪心)

nyoj914(二分搜索+贪心)

题目意思:

acm.nyist.net/JudgeOnline/problem.php?pid=914

现在有n个物品的重量和价值分别是Wi和Vi,你能帮他从中选出k个物品使得单位重量的价值最大吗?

输入
有多组测试数据
每组测试数据第一行有两个数n和k,接下来一行有n个数Wi和Vi。
(1<=k=n<=10000) (1<=Wi,Vi<=1000000)
输出
输出使得单位价值的最大值。(保留两位小数)
样例输入
3 2
2 2
5 3
2 1
样例输出
0.75
题目分析:

此题直接对单价进行贪心会出现问题,而且不难从样例上看出来。由于k个物品的单价一定不大于最大单价的物品,

而且一定会大于0,因此可以用二分搜素+贪心来解题。具体细节见注释


AC代码:

 
/**
 *贪心+二分搜索
 */
#include<iostream>
#include<cstring>
#include<cstdio>
#include<algorithm>
#define exp 1e-5
using namespace std;
typedef struct node{
    double w,v;
}node;
node p[10005];
double y[10005];
int n,k;
int cmp(double a,double b){
    if(a>b) return 1;
    return 0;
}
int Judge(double x){//二分搜索最大的且最恰当的值是否合理,if(合理)证明还有继续加大的空间,可以继续增大
    for(int i=0;i<n;i++){
        y[i]=p[i].v-p[i].w*x;
    }
    sort(y,y+n,cmp);
    double s=0;
    for(int i=0;i<k;i++){
        s+=y[i];
    }
    if(s>=0) return 1;
    else return 0;
}
double Search(double ma){
    double l=0,r=ma;
    while(r-l>exp){
        double mid=(l+r)/2;
        if(Judge(mid)){//当前值还小,还要增大
            l=mid;
        }
        else{//当前值大了,需要减小
            r=mid;
        }
    }
    return l;//或者return r;此时l=r
}
int main()
{
    while(scanf("%d%d",&n,&k)!=EOF){
        double ma=0;//k个最大平均值一定小于等于单个最大价值且大于0
        for(int i=0;i<n;i++){
            scanf("%lf%lf",&p[i].w,&p[i].v);
            if(ma<p[i].v/p[i].w) ma=p[i].v/p[i].w;
        }
        printf("%.2lf\n",Search(ma));
    }
    return 0;
}
       

nyoj914(二分搜索+贪心)