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; }

浙公网安备 33010602011771号