poj 3111 Status List (二分 + 贪心 最大化平均值)

@(K ACMer) by 题解工厂

题意:

有n个东西,每个东西的价值为x重量为y,从中选取k个东西,求价值重量比得最大值t.

分析:

典型的最大化平均值问题.如果不仔细思考容易按照贪心的思想去做,贪心是简单但是要基本确定他是对的再做!这里贪心就不对.
要满足:

x / y>=t

有:
xyt>=0

这里在根据 xyt 的取值来进行贪心的排序,选取前k个,就可以保证最终的均值最大.
这里我们对齐进行二分的值,相当于一个未知数,我们要把这个未知数带入不等式方程,才能更好地求解.

Code:

#include <iostream>
#include <cstdio>
#include <cmath>
#include <algorithm>
using namespace std;
const int M = int(1e5) + 9;
int n, k;
double maxcost, temp;
struct dot{int cost, weight, num;}a[M];

double max(double x, double y) {
    return x > y ? x : y;
}

bool cmp(dot a, dot b) {
    return a.weight - a.cost * temp > b.weight - b.cost * temp;
}

bool C(double x) {
    temp = x;
    sort(a, a + n, cmp);
    double ret = 0.0;
    for (int i = 0; i < k; i++) {
        ret += a[i].weight - a[i].cost * temp;
        //if (ret < 0) return false;
    }
    return ret >= 0;
}

void solve(void) {
    double l = 0, r = maxcost + 1;
    for (int i = 0; i < 100; i++) {
        double mid = (r + l) / 2;
        if (C(mid)) l = mid;
        else r = mid;
    }
    for (int i = 0; i < k; i++) {
        if (i) printf(" ");
        printf("%d", a[i].num);
    }
    printf("\n");
}

int main(void)
{
    while (~scanf("%d%d", &n, &k)) {
        maxcost = 0;
        for (int i = 0; i < n; i++) {
            scanf("%d%d", &a[i].weight, &a[i].cost);
            maxcost = max(a[i].weight / a[i].cost, maxcost);
            a[i].num = i + 1;
        }
        solve();
    }
    return 0;
}

你可能感兴趣的:(poj 3111 Status List (二分 + 贪心 最大化平均值))