编程题-最大化平均值-二分搜索

题目:

有n个物品的重量和价值分别为wi,vi,从中选取k个物品,使得单位重量的价值最大

样例:

输入:

n=3

k=2

(w,v)={ (2 , 2) , (5 , 3) , (2 , 1) }

输出

0.75(选0号和2号 ( 2 + 1)/( 2 + 2) = 0.75)

思路

首先想到的方法是先把物品按照单价排序,再从大到小进行选取。但是这样选出来的不一定是最优的,例如上面的案例,如果按照贪心算法 应该是选择 0号和1号, 结果为(2+3)/(2+5)=0.714。所以这个方法是不行的。

对于这个问题,使用二分搜索法可能很好的解决。我们定义:

条件C(x):=可以选择使得单位重量的价值不小于x

因此,原问题就变成了求满足C(x)的最大的x。

怎么判断C(x)是否可行呢?即判断是否

∑i∈kvi/∑i∈kwi≥x

把这个不等式变形就得到

∑i∈k(vi?x×wi)≥0

因此,原来的C(x):=vi?x×wi 从大到小排列,然后选出前k个的和大于等于0

代码:

#include <iostream>
#include <algorithm>
#include <cstdio>

using namespace std;

bool C(double x,int n,int k,int* w,int* v)
{
    //用于保存所有vi-x*wi
    double y[n];
    for(int i=0;i<n;i++){
        y[i]=v[i]-x*w[i];
    }
    sort(y,y+n);
    //计算后k个到和是否大于0 (因为是按照升序排序的)
    double sum = 0;
    for(int i=0;i<k;i++){
        sum+=y[n-i-1];
    }
    return sum>=0;
}

int main()
{
    int n,k;
    int max_value=0;
    cout<<"n = ";
    cin>>n;
    cout<<"k = ";
    cin>>k;
    int *w=new int[n];
    int *v=new int[n];
    for(int i=0;i<n;i++){
        cin>>w[i];
    }
    for(int i=0;i<n;i++){
        cin>>v[i];
        if(max_value<v[i])
            max_value=v[i];
    }

    double lb=0,ub=max_value;
    for(int i=0;i < 100;i++){
        double mid=(lb + ub )/2;
        if(C(mid,n,k,w,v))
            lb=mid;
        else
            ub=mid;
    }
    delete[] w,v;

    printf("%.2f\n",ub);

}

运行结果:

n = 3
k = 2
2 5 2
2 3 1
0.75
时间: 2024-11-10 12:03:54

编程题-最大化平均值-二分搜索的相关文章

POJ 3111 K Best &amp;&amp;NYOJ 914 (二分+ 贪心,最大化平均值)

链接:NYOJ:click here, POJ:click here 题意:(最大化平均值,挑战编程P143) 有n个物品的重量和价值分别是w[i]和v[i],从中选出K个物品使得单位重量的价值最大.(1<=k<=n<=10^41<=w[i],v[i]<=10^6) 一般想到的是按单位价值对物品排序,然后贪心选取,但是这个方法是错误的,比如对nyoj的例题来说,从大到小地进行选取,输入的结果是5/7=0.714对于有样例不满足.我们一般用二分搜索来做(其实这就是一个01分数规

上机操作编程题

一.写一个简单的缓存系统 1 package com.wisezone.demo; 2 3 import java.util.HashMap; 4 import java.util.Map; 5 /** 6 * 上机操作: 7 * 面试题--写一个简单的缓存系统 8 * @author 王东海 9 * @2017年6月5日 10 */ 11 public class CacheDemo 12 { 13 private Map<String, Object> map = new HashMap&

c++primerplus(第六版)编程题&mdash;&mdash;第6章(分支语句和逻辑运算符)

声明:作者为了调试方便,每一章的程序写在一个工程文件中,每一道编程练习题新建一个独立文件,在主函数中调用,我建议同我一样的初学者可以采用这种方式,调试起来会比较方便. (具体方式参见第3章模板) 1.编写一个小程序,读取键盘输入,直到遇到@符号为止,并回显输入(数字除外),同时将大写字符转换为小写,将小写字符转换为大写(别忘了cctype函数系列). #include <iostream> #include <cctype> using namespace std; void cp

二分算法的应用——最大化平均值

最大化平均值 有n个物品的重量和价值分别wi 和 vi.从中选出 k 个物品使得 单位重量 的价值最大. 限制条件: 1 <= k <= n <= 10^4 1 <= w_i <= v_i <= 10^6 输入:n = 3k = 2{W, V} = {(2,2), (5,3), (2,1)} 输出:0.75 (如果选0号和2号,平均价格是 (2 + 1) / (2 + 2) = 0.75) 题解: 一般先想到的肯定是:把物品按照  单位价值  进行排序,然后从大到小贪心

【二分查找-最大化平均值】POJ2976 - Dropping Test

[题目大意] 给出n组ai和bi,去掉k个使得a的总和除以b的总和最大. [思路] 也就是取(n-k)个数,最大化平均值,见<挑战程序设计竞赛>P144,最后公式为c(x)=((ai-x*bi)从大到小排列的前(n-k)个的和不小于0) 1 #include<iostream> 2 #include<cstdio> 3 #include<cstring> 4 #include<algorithm> 5 #include<cmath>

POJ C程序设计进阶 编程题#3:运算符判定

编程题#3:运算符判定 来源: POJ (Coursera声明:在POJ上完成的习题将不会计入Coursera的最后成绩.) 注意: 总时间限制: 1000ms 内存限制: 65536kB 描述 两个整数 a 和 b 运算后得到结果 c.表示为:a ? b = c,其中,?可能是加法 +,减法 -,乘法 *,整除 / 或 取余 %.请根据输入的 a,b,c 的值,确定运算符.如果某种运算成立,则输出相应的运算符,如果任何运算都不成立,则输出 error. 例如: 输入: 3,4,5 输出: er

中国MOOC_面向对象程序设计——Java语言_期末考试编程题_1细胞自动机

期末考试编程题 返回 这是期末考试的编程题 温馨提示: 1.本次考试属于Online Judge题目,提交后由系统即时判分. 2.学生可以在考试截止时间之前提交答案,系统将取其中的最高分作为最终成绩. 1 细胞自动机(30分) 题目内容: 这是细胞自动机的非图形版本.细胞自动机是指在一个二维网格内,每一个网格是一个细胞.每个细胞有活和死两种状态. 初始时刻,有些细胞是活的,有些细胞是死的.自动机的每一步,根据每个细胞周围8个格子内的其他细胞的生存情况决定这个细胞下一步是否存活.具体的规则如下:

京东校招笔试(C++方向)编程题

这次笔试是今年校招我参加的第一次笔试..出了很多状况,基础知识不扎实,导致选择题耽误了太多时间,导致后面的题目没做完,编程题也没有在 时间内写出来,基本没有面试机会了.不过我继续研究第二个编程题,在10几分钟后做了出来. 这个题目具体已经不记得了,但是大概意思还是记得,我们把由4和7组成的数,按小大排序,例如:4 7 44 47 74 77 444 447 474 477 744 747 774 777 他们的序号依次为1,2,3,4.....,题目的输入是每行输入一个整数,可以很大(好像是最大

网易有道内推编程题

[编程题] 洗牌 洗牌在生活中十分常见,现在需要写一个程序模拟洗牌的过程. 现在需要洗2n张牌,从上到下依次是第1张,第2张,第3张一直到第2n张.首先,我们把这2n张牌分成两堆,左手拿着第1张到第n张(上半堆),右手拿着第n+1张到第2n张(下半堆).接着就开始洗牌的过程,先放下右手的最后一张牌,再放下左手的最后一张牌,接着放下右手的倒数第二张牌,再放下左手的倒数第二张牌,直到最后放下左手的第一张牌.接着把牌合并起来就可以了. 例如有6张牌,最开始牌的序列是1,2,3,4,5,6.首先分成两组