Yougth的最大化
- 描述
Yougth现在有n个物品的重量和价值分别是Wi和Vi,你能帮他从中选出k个物品使得单位重量的价值最大吗?
- 输入
- 有多组测试数据
每组测试数据第一行有两个数n和k,接下来一行有n个数Wi和Vi。
(1<=k=n<=10000) (1<=Wi,Vi<=1000000) 输出 - 输出使得单位价值的最大值。(保留两位小数) 样例输入
3 2 2 2 5 3 2 1
样例输出0.75
- 有多组测试数据
乍一看这道题,和我前几天做的二分答案题不大一样了(才入门二分)
然后就很纠结啊...一开始连二分的上限是什么都没找到
后来发现 其实二分的上限 就是max(v[i]/w[i]){i=1,2,3,...,n}
为什么呢?我数学渣,证明不来,但是你感受一下,不可能有较小的加上最大的反而还比最大的大这种鬼事情吧
继续,现在二分的左边,右边都已经确定,那怎么check呢
先假定有一个集合S 使得下面这个式子成立
sum(v[i])/sum(w[i])>=mid
这其中 sum(v[i]),sum(w[i])是集合S中的v元素和和w元素和
我们要尝试确定是否有这个S
不等式变形
就变成了sum(v[i])-sum(w[i])*mid>=0
那岂不就是sum(v[i]-w[i]*,mid)>=0?
可是现在,集合S我们无法确定到底有哪些元素
那干脆把所有的元素全部算一遍(v[i]-w[i]*mid)
递减排序后,取其前k个,如果这k个的和>=0,那这个集合S就是存在滴!
上一步就是一个很巧妙的贪心
讲完啦 看代码吧!
#include<bits/stdc++.h>
using namespace std;
double w[10005],v[10005];
double y[10005];
double max_ave=-999;
int n,k;
bool get(double x)
{
int i;
double sum=0;
for(i=0;i<n;i++)
{
y[i]=v[i]-x*w[i];
}
sort(y,y+n);
for(i=0;i<k;i++)
{
sum+=y[n-i-1];
}
return sum>=0;
}
double bin()
{
double low,high,mid;
low=0.0;
high=max_ave;
for(int i=0;i<100;i++)
{
mid=(low+high)/2;
if(get(mid)) low=mid;
else high=mid;
}
printf("%.2lf\n",high);
}
int main()
{
int i,j;
while(scanf("%d%d",&n,&k)!=EOF)
{
for(i=0;i<n;i++)
{
scanf("%lf%lf",&w[i],&v[i]);
max_ave=max(max_ave,v[i]/w[i]);
}
bin();
}
return 0;
}