
小咪是一个土豪手办狂魔,这次他去了一家店,发现了好多好多(n个)手办,但他是一个很怪的人,每次只想买k个手办,而且他要让他花的每一分钱都物超所值,即:买下来的东西的总价值/总花费=max。请你来看看,他会买哪些东西吧。
题目
- 原题地址:小咪买东西
- 题目编号:NC14662
- 题目类型:01分数规划
- 时间限制:C/C++ 1秒,其他语言2秒
- 空间限制:C/C++ 131072K,其他语言262144K
1.题目大意
- n个物品,有价值v和价格c,选出k个物品,求max(总价值/总价格)
2.题目分析
- 感觉不是很懂为啥用二分。。。按照原来思路做WA了(直接按照v/c比排序,再加和相除)
- 想明白了:
- 原来的思路:直接按照v/c比排序,再选出前k个加和,总的v和总的c相除
- 正确的思路:二分单位价值x,check函数里按照v-c*x来排序,如果前k个的v-c*x之和>0,就返回true
- 为什么原来的思路不对:就是因为靠后的物品如果vc都大,会把最终结果向它靠近,不如选择v/c小的,让其影响不了大v/c的物品占比多少
- eg:8,2;9,3;40,20;1,1
- (8+9+40)/(2+3+20)=57/25<3
- (8+9+1)/(2+3+1)=3
3.题目代码
#include <bits/stdc++.h>
using namespace std;
const int INF = 0x3f3f3f3f;
const int MAX = 1e4 + 7;
int n, k;
int c[MAX], v[MAX];
double w[MAX];
bool judge(double x) {
for (int i = 1; i <= n; i++)
w[i] = v[i] - x * c[i];
sort(w + 1, w + 1 + n, greater<double>());
double sm = 0;
for (int i = 1; i <= k; i++)
sm += w[i];
return sm > 0;
}
int main() {
int t;
cin >> t;
while (t--) {
cin >> n >> k;
for (int i = 1; i <= n; i++)
cin >> c[i] >> v[i];
double l = 0, r = INF;
for (int i = 1; i <= 100; i++) {
double mid = (l + r) / 2;
if (judge(mid)) l = mid;
else r = mid;
}
cout << (int)r << endl;
}
return 0;
}