POJ 3111 K Best 二分(最小化平均值)
阿新 • • 發佈:2019-01-25
題目:
題意:
給定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;
}