zoukankan      html  css  js  c++  java
  • [USACO18OPEN]Talent Show(分数规划+01背包)

    传送门

    题意:N头牛,第i头牛重量wi,价值vi,选出总重量至少为W的牛,使得总价值与总重量的比值最大?

    看到这种类似于一个物品有多个属性,且题目最后要求各属性总和比值最大的问题,就要想到分数规划.理解题意,我们要求的答案就是(frac{sum vi}{sum wi}),且(sum wi>=W)

    我们直接二分比值mid(为什么可以二分,我在其它关于分数规划的题解里讲得比较清楚了),如果本次二分的值成立,即(frac{sum vi}{sum wi}>=mid),且(sum wi>=W)

    整理一下上式得(sum (vi-wi*mid)>=0),且(sum wi>=W)

    所以我们可以在每次check时,把每头奶牛的价值视作(vi-wi*mid),然后题目就转换为了,已知物品的价值和重量,选出总重量不小于W的物品,使价值和>=0.这不就类似于01背包问题?

    只是在跑01背包的时候注意一个问题,一般的01背包问题都是背包容量不超过W,而本题物品总重量却是要求不小于W,所以我们可以把超过W的全都压在W里面,具体见代码实现.

    int n,W,w[300],t[300];
    double eps=1e-8,v[300],f[1005];
    //因为是实数二分,随便设置了个精度eps
    bool check(double mid){
        for(int i=1;i<=W;i++)f[i]=-1e9;
    //因为要求最大值,初值就设为负无穷.
        for(int i=1;i<=n;i++)
    		v[i]=t[i]-w[i]*mid;
    //每次check时根据mid更新每头奶牛的价值
        for(int i=1;i<=n;i++)
    	for(int j=W;j>=0;j--){
    	    if(w[i]+j>W)f[W]=max(f[W],f[j]+v[i]);
    	    else f[w[i]+j]=max(f[w[i]+j],f[j]+v[i]);
    	}
    //一般的01背包都是f[j]=max(f[j],f[j-w[i]+v[i])
    //但因为我们选的物品总重量只有下限,没有上限,
    //所以我们这里写作:如果没选这件物品,容量j就加上w[i]
    //如果选了这件物品,直接总价值f[j]加上v[i]
    //然后如果容量j+w[i]超过W,还是压在f[W]里面
        return f[W]>=0;
    //价值和>=0说明本次二分的mid合法
    }
    int main(){
        n=read();W=read();
        for(int i=1;i<=n;i++){
    		w[i]=read();
    		t[i]=read();
        }
        double l=0,r=1e9,mid;
        while(l+eps<r){
    		mid=(l+r)/2.0;
    		if(check(mid))l=mid;
    		else r=mid;
        }
        printf("%d
    ",(int)(l*1000));
    //按照题目要求输出
        return 0;
    }
    
    
  • 相关阅读:
    Linux ,Ubuntu 分区建议大小
    [No000019A]【波浪理论精典教学课程】
    CS(计算机科学)知识体
    如何量化考核技术人的KPI?
    Linux系统的命令应该如何记?
    数学和物理太难?这些 GIF 让你秒懂抽象概念
    加密数字货币的 7 个致命悖论
    量子力学中,全体自然数之和是负十二分之一,物理意义是什么?
    30岁左右的人,来谈谈你犯了哪些错误?
    一篇文章学懂Shell脚本,最简明的教程在这里
  • 原文地址:https://www.cnblogs.com/PPXppx/p/10368009.html
Copyright © 2011-2022 走看看