单位质量最大价值问题

来源:互联网 发布:mac键盘切换输入法 编辑:程序博客网 时间:2024/04/29 18:36

描述:

有n个物品,单个物品的质量为w(weigh),价值为v(value),要从n个物品中选取k个,求再所有的选取方案中,能获得的最大单位质量价值。也就是k个物品总的价值V / 总的质量W。保留两位小数。


说明:

一般最先想到的方法是把每个物品按照单位价值排序,从大到小贪心进行选取。但这种方法是不正确的。举一个反例就好了。

比如说:n = 3, k = 2,(w, v) = {(2,2),(5,3),(2,1)},按照之前的策略应该选第一和第二物品,得到的平均价值为5/7 = 0.714。

但如果我们选择第一和第三个物品的话,结果就是3/4 = 0.75。所以说要想别的办法。

定义条件 C(x):= 可以选择使得单位重量的价值不小于x

原问题变成了求满足C(x)的最大x的问题。如何判断C(x)为真呢,假设我们选了k个物品,组成的集合为S,那么它们的单位质量价值是 Σv / Σw。

因此就变成了判断是否存在S满足条件 Σv / Σw >= x,变形得到 Σ(vi - x * wi) >= 0 。

因此,对vi - x * wi 的值进行排序,贪心的进行选取,最后问题变成了

C(x):((vi - x * wi) 从大到小排列中前k个和不小于0)   每次判断排序依次复杂度O(nlogn)。


完整实现代码如下:

#include <iostream>#include <algorithm>using namespace std;const int MAX_N = 1000;const double MAX_X = 1000000.0;int n, k;int w[MAX_N], v[MAX_N];double y[MAX_N];// v - x * wbool C(double x){for (int i = 0; i < n; i++)y[i] = v[i] - x * w[i];sort(y, y + n);// 计算y数组中从大到小前k个数的和double sum = 0.0;for (int i = 0; i < k; i++)sum += y[n - 1 - i];return sum >= 0;}int main(){cin >> n >> k;for (int i = 0; i < n; i++)cin >> w[i] >> v[i];double lb = 0.0, ub = MAX_X;for (int i = 0; i < 100; i++){double mid = (lb + ub) / 2;if (C(mid))lb = mid;elseub = mid;}printf("%.2f\n", ub);}

结果:


ps:这个主要在《挑战程序设计竞赛》上看到的,感觉非常巧妙。搬上来跟大家分享下。也强烈推荐这本书。

0 0
原创粉丝点击