zoukankan      html  css  js  c++  java
  • NYOJ 914 Yougth的最大化【二分/最大化平均值模板/01分数规划】

    914-Yougth的最大化

    内存限制:64MB 时间限制:1000ms 特判: No

    通过数:3 提交数:4 难度:4

    题目描述:
    Yougth现在有n个物品的重量和价值分别是Wi和Vi,你能帮他从中选出k个物品使得单位重量的价值最大吗?

    输入描述:
    有多组测试数据
    每组测试数据第一行有两个数n和k,接下来一行有n个数Wi和Vi。
    (1<=k=n<=10000) (1<=Wi,Vi<=1000000)
    输出描述:
    输出使得单位价值的最大值。(保留两位小数)
    样例输入:
    复制
    3 2
    2 2
    5 3
    2 1
    样例输出:
    0.75

    【分析】:

        Q:有n个价值和重量为vi、wi的物品,从中挑选k个使单位重量的价值最大
    
        A:
        此题不能直接用贪心法:直接按物品的单位价值排序,然后依次取k个;
        我们要求的最大值是,价值之和/重量之和;而上面所说是单位价值之和。
        ------------------------------------------变形贪心
        二分搜索法模型:
        条件C(x):可以挑选使得单位重量的物品价值不小于x->求满足条件的最大x->如何判断C(x)
        价值和/重量和>=x
        价值和-重量和*x>=0
        和(价值-重量*x)>=0
        可以对(价值-重量*x)的值进行贪心的选取,选取最大的k个 和>=0
    

    和最大化最小值类似,最大化平均值也可以通过二分法求得。

    比如下面这个经典的问题:
    有n个物品的重量和价值分别是wi和vi,从中选出k个物品使得单位重量价值最大。

    样例输入:

    3 2
    2 2
    5 3
    2 1
    1
    2
    3
    4
    5
    样例输出:

    0.75

    分析:
    一般先想到的是将每个物品的单位重量价值算出来,然后排个序,从大到小贪心进行选择,可惜这样是不对的,这样不能保证最后一定是最大平均值,直接用贪心对于这类要涉及多个因素比如求最大平均值的问题就显得不那么正确了。

    那么我们这样分析这个问题:
    令C(x)为可以选择使得单位重量的价值不小于x。
    这样就可以用二分法来解决,不断二分x进行判断,取最大。

    我们继续分析:

     ∑vi / ∑wi 这个式子是我们需要求的单位重量的价值。 
     i∈s   i∈s
    

    那么就求是否满足:

     ∑vi / ∑wi >= x
     i∈s   i∈s
    

    转换一下得到:

    ∑(vi - x*wi) >= 0
    i∈s 
    

    判断这个式子是否成立即可。这下就可以用一个数组来保存vi - x * wi 的值,并进行排序,从大到小贪心地进行选择求和,如果求和的值大于0,那么此时 的x就是成立的。

    【代码】:

    #include<bits/stdc++.h>
    
    const double eps = 1e-8;
    const int maxn = 1e6+5;
    #define inf 0x3f3f3f3f
    #define ll long long
    using namespace std;
    /*
    有n个物品的重量和价值分别是wi和vi
    从中选出k个物品使得单位重量价值最大
    
    */
    int n,k;
    int w[maxn],v[maxn];
    double y[maxn];
    bool cmp(int a,int b)
    {
        return a>b;
    }
    bool check(double x)
    {
        for(int i=0;i<n;i++)
            y[i] = v[i] - w[i] * x;
        sort(y,y+n);
        double sum = 0;
        for(int i=0; i<k; i++)
            sum += y[n-i-1];
        return sum>=0;
    }
    void solve()
    {
        double l = 0, r =inf, mid;
        for(int i=0;i<100;i++)
        {
            mid = (l+r)/2;
            if(check(mid))
                l=mid;
            else r=mid;
        }
        printf("%.2f
    ",r);
    }
    int main()
    {
        while(~scanf("%d%d",&n,&k))
        {
            for(int i=0;i<n;i++)
                cin>>w[i]>>v[i];
            solve();
        }
    }
    
    
  • 相关阅读:
    对MVC模型的自悟,详尽解释,为了更多非计算机人员可以理解
    openSUSE leap 42.3 实现有线 无线同时用
    Fedora27 源配置
    Ubuntu16.04添加HP Laserjet Pro M128fn打印机和驱动
    openSUSE leap 42.3 添加HP Laserjet Pro M128fn打印机和驱动
    OpenSUSE Leap 42.3下通过Firefox Opera Chromium浏览器直接执行java应用程序(打开java jnlp文件)实现在服务器远程虚拟控制台完成远程管理的方法
    OpenSUSE Leap 42.3 安装java(Oracle jre)
    linux下支持托盘的邮件客户端Sylpheed
    Ubuntu下通过Firefox Opera Chromium浏览器直接执行java应用程序(打开java jnlp文件)实现在服务器远程虚拟控制台完成远程管理的方法
    Firefox 浏览器添加Linux jre插件
  • 原文地址:https://www.cnblogs.com/Roni-i/p/9359674.html
Copyright © 2011-2022 走看看