1. 程式人生 > >POJ 3111 K Best 二分(最小化平均值)

POJ 3111 K Best 二分(最小化平均值)

題目:

題意:

給定n個物品,每個物品有價值和重量,現在從其中選出k個物品,使這些物品的單位價值最大,並輸入一組選擇方案(任一組)

思路:

一般思路是對物品按單位價值排序取前k個,然而這樣是不對的,可以找到反例。單位重量的價值為sum(v[i]) / sum(w[i]),於是列舉單位重量價值x,就變成了sum(v[i]) / sum(w[i]) >= x,sum(v[i] - x * w[i]) >= 0,找到滿足上述不等式的最大x值(來自挑戰程式設計競賽)

#include <iostream>
#include <cstring>
#include <cstdio>
#include <algorithm> #include <vector> #include <cmath> #include <queue> using namespace std; const int N = 100010, INF = 0x3f3f3f3f; struct node { double val; int idx; friend bool operator< (node a, node b) { return a.val > b.val; } } arr[N]; int
n, k; int w[N], v[N], res[N]; bool work(double mid) { for(int i = 1; i <= n; i++) arr[i].idx = i, arr[i].val = v[i] - mid * w[i]; sort(arr + 1, arr + 1 + n); double sum = 0; for(int i = 1; i <= k; i++) sum += arr[i].val, res[i] = arr[i].idx; return sum >= 0; } int
main() { while(~ scanf("%d%d", &n, &k)) { for(int i = 1; i <= n; i++) scanf("%d%d", &v[i], &w[i]); double l = 0.0, r = INF; //for(int i = 1; i <= 100; i++)//用這個會超時 while(r - l > 1e-6) { double mid = (l + r) / 2; if(work(mid)) l = mid; else r = mid; } for(int i = 1; i <= k; i++) printf("%d%c", res[i], i == k ? '\n' : ' '); } return 0; }