POJ 3111(二分&三分_D题)解题报告

题目链接:http://poj.org/problem?id=3111

--------------------------------------------------------

题意:n个珠宝,保留k个,每个珠宝有重量和价值,问k个珠宝总价值/总重量的最小值是多少。

思路:本题是非常好的二分法的经典例题,考察了对于二分法的理解,在二分法使用过程中,一定要明白二分求值的要求是什么,即评判标准是什么?在本题中要求的是S,所以每步需要找到v[i]-w[i]*S最近的值,表示对S的正作用最大的值,想到这里,也就明白了本题使用二分法的评判标准了。不同于其他二分的是,在每次计算时,都需要进行重新排序。

代码:

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<iostream>
#include<string>
#include<vector>
#include<stack>
#include<bitset>
#include<cstdlib>
#include<cmath>
#include<set>
#include<list>
#include<deque>
#include<map>
#include<queue>
using namespace std;
typedef long long ll;
const double PI = acos(-1.0);
const double eps = 1e-6;
int k=0;
int n=0;
const int MAXN =1e5+100;
int a[MAXN]; 
int b[MAXN];
double as[MAXN];
int index[MAXN];
double MN;
bool cmp(int a,int b){
    return as[a]>as[b];
}
int jud(double d){
    for(int i=0;i<n;i++){
        as[i]=1.0*a[i]-b[i]*d;
        index[i]=i;
    }
    sort(index,index+n,cmp);
    double res=0;
    for(int i=0;i<k;++i){
        res+=as[index[i]];
    }
    return res>=0;
}
double bsearch(){
    double left =0;
    double right =MN;
    double mid=(right+left)/0.5;
    while((right-left)>eps){
        mid=(right+left)*0.5;
        if(jud(mid)){
            left=mid;
        }else{
            right =mid;
        }
    }
    return 0;
} 


int main(void){
    scanf("%d%d",&n,&k);
    for(int i=0;i<n;i++){
        scanf("%d%d",&a[i],b+i);
        MN=max(MN,1.0*a[i]/b[i]);
    }
    MN+=10;
    bsearch();
    for(int i=0;i<k;i++){
        printf("%d%c",index[i]+1,(i==(k-1))[" \n"]);
    }
    return 0;

}
View Code

 

posted @ 2018-01-23 23:50  caomp  阅读(92)  评论(0)    收藏  举报