题目:
http://poj.org/problem?id=3111
题意:
给定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;
}