Yougth的最大化
时间限制:1000 ms | 内存限制:65535 KB
难度:4
- 描述
-
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
典型的0-1分数规划问题,用二分+贪心求解
首先必须知道单位重要的的最大价值的取值范围,其最小为0,最大不超过单个物品的单位重量的最大价值
证明如下:
假设第i个物品的单位重量的价值最大,则对于任意的第j个物品的有Vj/Wj<=Vi/Wi 即 Vi*Wj-Vj*Wi >= 0
则j,i两个物品的单位重量的价值为(Vi+Vj)/(Wi+Wj),
则Vi/Wi-(Vi+Vj)/(Wi+Wj) = (Vi*Wj-Vj*Wi)/(Wi*(Wi+Wj)) >=0
即Vi/Wi>=(Vi+Vj)/(Wi+Wj)
故单位重量的的最大价值不超过单个物品的单位重量的最大价值找到单位重量的的最大价值的范围既可以用二分搜索找到满足条件的值即可
由于(v1+v2+...+vk)/(w1+w2+...+wk) = value
则(v1+v2+...+vk)=value*(w1+w2+...+wk)
二分搜索时
如果value比单位重量的最大值大,则(v1+v2+...+vk)-value*(w1+w2+...+wk) < 0 说明所求的值小于value
如果value比单位重量的最大值小,则(v1+v2+...+vk)-value*(w1+w2+...+wk) > 0 说明所求值大于value#include <iostream> #include <vector> #include <algorithm> #include <numeric> #include <cstdio> using namespace std; struct Good{ float w; float v; Good(double ww=0.0, double vv=0.0):w(ww),v(vv){} }; vector<Good> goods(10005); int n,k; bool judge(float value){ vector<float> diffValue(n); for(int i = 0 ; i < n; ++ i) diffValue[i] = goods[i].v-goods[i].w*value; sort(diffValue.begin(),diffValue.end()); float sum = accumulate(diffValue.rbegin(),diffValue.rbegin()+k,0.0); return sum >= 0 ? true:false; } float binarySearch(float maxv){ float left = 0, right = maxv; for(int i = 0; i < 100; ++ i){ float mid =(left+right)/2; if(judge(mid)) left = mid; else right = mid; } return left; } int main(){ while(cin >>n >> k){ float maxv = 0; for(int i = 0 ; i < n; ++i){ cin >>goods[i].w >>goods[i].v; maxv = max(maxv,goods[i].v/goods[i].w ); } printf("%0.2f ",binarySearch(maxv)); } }