POJ 3111 K Best ( 二分 )

Posted rubbishes

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了POJ 3111 K Best ( 二分 )相关的知识,希望对你有一定的参考价值。

题意 : 给出 N 个物品的价值和重量,然后要求选出 K 个物品使得选出来物品的单位重量价值最大,最后输出被选物品的编号。

 

分析 : 

很容易去想先算出每个物品的单位价值然后升序排序取前 K 个,但是很可惜这样的做法是错误的。

例如 : N = 3、K = 2、{ w、v } = { {2,2}、{5,4}、{2,1} },贪心的方法是选出 1、2,但是正确答案是选出1、3

这题的正确做法是利用二分,难点就在如何判定二分出来的每一个单位重量价值是否是一个可行答案

假设当前二分出来的答案是 x

那么就要求选出来的前 K 个物品 ∑ vi / ∑ wi ≥ x

变形得到 ∑ ( vi - wi * x ) ≥ 0

那么最后就变成了对于当前的 x 对所有物品的 vi - wi * x 进行排序

并判断前 K 大的是否大于等于 0 ,如果是则说明可行!

 

技术分享图片
#include<algorithm>
#include<stdio.h>
#include<math.h>
using namespace std;
const int maxn = 1e5 + 10;
const double EPS = 1e-8;
const double INF = 10000000;
struct Jewel{ int id, v, w; }arr[maxn];
struct st{
    double val; int id;
    bool operator < (const st & rhs) const{
        return this->val > rhs.val;
    };
}c[maxn];
int N, K, ans[maxn];

bool OK(double key)
{
    for(int i=1; i<=N; i++){
        c[i].val = arr[i].v - arr[i].w * key;
        c[i].id = arr[i].id;
    }
    sort(c+1, c+1+N);
    double sum = 0;
    for(int i=1; i<=K; i++)
        sum += c[i].val;
    if(sum >= 0.0){
        for(int i=1; i<=K; i++)
            ans[i] = c[i].id;
        return true;
    }else return false;
}

int main(void)
{
    while(~scanf("%d %d", &N, &K)){
        for(int i=1; i<=N; i++){
            if(i <= K) ans[i] = i;///注意要提前给 ans 赋上初值,因为 OK 函数可能永远不为真,例如所有物品的 v = 0
            arr[i].id = i;
            scanf("%d %d", &arr[i].v, &arr[i].w);
        }

        double L = 0.0;
        double R = INF;
        while(R - L > EPS){
            double mid = ( R + L ) / 2.0;
            if(OK(mid)) L = mid;
            else R = mid;
        }

        for(int i=1; i<=K; i++){
            printf("%d", ans[i]);
            if(i < K) putchar( );
            else putchar(\n);
        }
    }
    return 0;
}
View Code

 

以上是关于POJ 3111 K Best ( 二分 )的主要内容,如果未能解决你的问题,请参考以下文章

POJ - 3111 K Best (二分查找)

POJ 3111 K Best 二分 最大化平均值

POJ 3111 K Best(二分答案)

POJ3111 K Best(另类背包+二分+变态精度)

POJ3111 K Best —— 01分数规划 二分法

POJ 3111 K Best ( 二分 )