P1570 KC喝咖啡
题意:给出n种咖啡材料,每种材料有美味度和消耗时间
要求下m种材料(只能刚好是m种)
问下哪些能够得到的平均美味度最大(平均为所有的美味度除以所有的消耗时间)
思路:一开始想的时候,很容易能够想到一种贪心做法,就是按照美味度和消耗时间的比值从大到小排序
然后取前m个,但是很快就能够发现这种做法是错误的;
因为除了比值以外,数值的基数也很重要,比如有一个10000美味度的、10000消耗时间的材料
然后假如再放一些数值很小很小的材料,就会发现几乎忽略不计
所以并不是比值越大越好,还要考虑基数
那这有点难办了,直接贪心做不了,所以我们得换个思路,采用二分的方式
我们二分对象为平均美味度
那么如何check呢? 我们需要将原数组做一些改变
for(int i=1;i<=n;i++) tmp[i]=G[i].x-mid*G[i].y;
我们可以根据此式子求出所有的数,然后从大到小排序,找出m个数,假如大于0,则满足,反之不满足
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 #include<bits/stdc++.h> 2 using namespace std; 3 const int maxn=1000; 4 double tmp[maxn]; 5 struct node 6 { 7 double x,y; 8 }G[maxn]; 9 int n,m; 10 bool cmp(int t1,int t2) 11 { 12 return t1>t2; 13 } 14 int check(double mid) 15 { 16 for(int i=1;i<=n;i++) 17 tmp[i]=G[i].x-mid*G[i].y; 18 sort(tmp+1,tmp+1+n,cmp); 19 double sum=0; 20 for(int i=1;i<=m;i++){ 21 sum+=tmp[i]; 22 } 23 if(sum>=0) return 1; 24 else return 0; 25 } 26 int main() 27 { 28 scanf("%d%d",&n,&m); 29 for(int i=1;i<=n;i++){ 30 scanf("%lf",&G[i].x); 31 } 32 for(int i=1;i<=n;i++){ 33 scanf("%lf",&G[i].y); 34 } 35 double L=0;double R=1000; 36 while((R-L)>=1e-6){ 37 double mid=(L+R)/2; 38 if(check(mid)){ 39 L=mid; 40 } 41 else R=mid; 42 } 43 printf("%.3f\n",L); 44 return 0; 45 }