2018年东北农业大学春季校赛 I-wyh的物品

xiaoxiao2021-02-28  21

2018年东北农业大学春季校赛 I-wyh的物品

链接:https://www.nowcoder.com/acm/contest/93/I

来源:牛客网

题目描述

wyh学长现在手里有n个物品,这n个物品的重量和价值都告诉你,然后现在让你从中选取k个,问你在所有可能选取的方案中,最大的单位价值为多少(单位价值为选取的k个物品的总价值和总重量的比值)

输入描述:

输入第一行一个整数T(1<=T<=10)

接下来有T组测试数据,对于每组测试数据,第一行输入两个数n和k(1<=k<=n<=100000)

接下来有n行,每行两个是a和b,代表这个物品的重量和价值

输出描述:

对于每组测试数据,输出对应答案,结果保留两位小数

示例1

输入

1 3 2 2 2 5 3 2 1

输出

0.75

说明

对于样例来说,我们选择第一个物品和第三个物品,达到最优目的

思路

咋眼一看(其实看了也很久),以为是背包(一直往背包方向上靠)。

但其实这是求一个最大化的平均值(使用二分法)。

这可能有点难理解。我们不妨把(目标要求的)单位价值设为x,差值为y。

y = 重量 * x - 价值

为了保证x最大,我们取y值前k大的(重量,价值)对。

对于每组(重量,价值)对,逐一计算出y值,然后递增排列,取前k个计算得出(总质量,总价值)。

使用二分寻找出目标x,对应差值y应接近于0:

y = 总重量 * x - 总价值 (y → 0)

使用二分缩小x取值范围,直到满足规定的最小精度。

AC代码

#include <iostream> #include <vector> #include <algorithm> #include <iomanip> using namespace std; struct things { double a; // 重量 double b; // 价值 }; double low,mid,high; bool cmp(things fir, things sec) { return mid * fir.a - fir.b < mid * sec.a - sec.b; } int main() { int T; cin >> T; while(T--) { int n,k; cin >> n >> k; vector<things> vec; for(int i=0; i<n; i++) { double a,b; cin >> a >> b; things th; th.a = a; th.b = b; vec.push_back(th); } double value, weight, ans; double res; // 差值 low = 0, high = 1000,ans = 0; while(high-low > 1e-6) { mid = (low + high) / 2.0; sort(vec.begin(), vec.end(), cmp); value = weight = 0; for(int i = 0; i < k; i++) { things tmp = vec.at(i); value += tmp.b; weight += tmp.a; } ans = value / weight; res = mid * weight - value; if(res < 0) low = mid; else high = mid; } //cout << mid << endl; cout << fixed << setprecision(2) << ans << endl; } return 0; }
转载请注明原文地址: https://www.6miu.com/read-2629802.html

最新回复(0)