练习了下二分,找到这道二分的题,题目很不错,是变形的二分,自己想真的很难想到转化成二分处理。
既然是求最大的单位重量的价值,那么就是求(v1+...+vk)/(w1+...+wk)=x,x的最大值。
式子变形满足vk-x*wk=0的和。等于0时为最优。二分查找x值即可。
算出每一个物品的最大单位重价值,从大到小排序求得前K项的和。满足等式就输出。
想了半天处理物品标号问题,最后还是用了结构体,加上自定义快排,很好的处理了输出细节。
PS:用for循环100次会超时,所以还是找到边界就退出比较好。
#include <iostream>
#include <cstdio>
#include <cstring>
#include <cmath>
#include <algorithm>
#include <iomanip>
using namespace std;
const int maxn=1e5+5;
struct P
{
int h;
int v;
int w;
double val;
} kp[maxn];
int arr[maxn];
bool cmp(const P & a,const P & b)
{
if(a.val>b.val) return true;
return false;
}
int main()
{
int n,k;
while(scanf("%d%d",&n,&k)==2)
{
memset(arr,0,sizeof(arr));
double l=0,r=0;
for(int i=0; i<n; i++)
{
scanf("%d%d",&kp[i].v,&kp[i].w);
kp[i].h=i;
r=max(r,kp[i].v*1.0/kp[i].w);
}
while(r-l>=1e-6)
{
double mid=(r+l)/2;
for(int i=0; i<n; i++)
kp[i].val=kp[i].v-kp[i].w*mid;
sort(kp,kp+n,cmp);
double sum=0;
for(int i=0; i<k; i++)
sum+=kp[i].val;
if(sum>0) l=mid;
else if(sum<0) r=mid;
else break;
}
for(int i=0; i<k; i++)
arr[i]=kp[i].h+1;
sort(arr,arr+k);
for(int i=0; i<k-1; i++)
printf("%d ",arr[i]);
printf("%d\n",arr[k-1]);
}
return 0;
}