https://vjudge.net/problem/POJ-2976
给定n个人,有两种分数,a,b
要求你选取一部分,要求 sigma(a)/sigma(b) *100得值最大。
化简式子
枚举的mid 不断的逼近最优解。 设定一个精度。
#include <iostream>
#include <cstring>
#include <cstdio>
#include <algorithm>
using namespace std;
/* 01分数规划 可以用二分,或者用一种递推。
思路是 不断的维护一个最优解。
因为暴力计算最优解,是不可行的,因为他要找那么那么多那么多组合
而01分数规划是通过对 式子的转化。
如果 sigma(x1-y1*mid) 大于0,如果当前选择的 分数构成的比例已经大于mid
也就是说,必然存在一个更优的解(因为我们当前计算就已经比他优了)
那为什么不用我们 现在计算的那个点呢,
因为可能有些选择比他更优,
(如果没有比他更优的话,最后不断的二分,mid会不断的回退到这里)
*/
const int maxn=3000;
const double eps=1e-5;
double a[maxn];
double b[maxn];
double aa[maxn];
bool cmp2(double a,double b){
return a<b;
}
int main()
{ int m,k;
while(~scanf("%d%d",&m,&k)){
if(!m&&!k) break;
for(int i=0;i<m;i++){
scanf("%lf",&a[i]);
}
for(int i=0;i<m;i++){
scanf("%lf",&b[i]);
}
double l=0.0;
double r=1.0;
double ans=0;
double mid;
while(r-l>=eps){
mid=(r+l)/2;
//cout<<mid<<endl;
double sum=0;
for(int i=0;i<m;i++){
aa[i]=a[i]*1.0-b[i]*mid;
}
sort(aa,aa+m,cmp2);
for(int i=k;i<m;i++){
sum+=aa[i];
}
if(sum>=0){
l=mid;
ans=mid;
}
else
r=mid;
}
printf("%.0f\n",ans*100);
}
return 0;
}