• 51Nod1257 背包问题 V3


    题目看这里

    01分数规划入门题

    这道题有非常经典的错误解法:按照pi/wi排序

    这样是不能保证答案最大的,反例(本体样例)已经有了

    那么我们来考虑怎么做

    首先我们二分这个答案ans

    让后我们给每个物品i设置一个权值v[i]=p[i]-ans*w[i]

    所有物品按照v排序,取前k大求和

    那么如果ans是正确答案,那么显然,这个和S=0

    如果ans大于正确答案,S<0

    如果ans小于正确答案,S>0

    发现是满足二分的单调性的,所以这样是对的,复杂度O(n log n log pi)

    不过还有一种更加快的迭代的做法

    我们将所有物品按照v排序,取前k大的物品计算一下∑pi/∑wi的值res,如果ans和res差别很小就可以直接退出

    否则令ans=res,重复上面过程

    这个过程感觉很玄学,没有二分清晰,但是跑的很快

    我的代码(二分)

    #include<stdio.h>
    #include<string.h>
    #include<algorithm>
    #define N 50010
    #define LL long long
    using namespace std;
    int n,m,w[N],p[N],r[N]; LL x,y,c,a,b; double s[N],l=0,_r=50000;
    inline bool cmp(int x,int y){ return s[x]>s[y]; }
    inline int ok(double k){
        double S=0;
        for(int i=1;i<=n;++i) s[r[i]=i]=p[i]-w[i]*k;sort(r+1,r+1+n,cmp);
        for(int i=1;i<=m;++i) S+=s[r[i]];
        return S>=0;
    }
    int main(){
        scanf("%d%d",&n,&m);
        for(int i=1;i<=n;++i) scanf("%d%d",w+i,p+i);
        for(double M;_r-l>1e-6;ok(M)?l=M:_r=M) M=(l+_r)/2.;
        for(int i=1;i<=m;++i) x+=w[r[i]],y+=p[r[i]];
        for(a=x,b=y;b;a=b,b=c) c=a%b;
        printf("%lld/%lld",y/a,x/a);
    }

  • 相关阅读:
    对list集合中的对象进行排序(转载)
    关键字的作用
    CocoaPods的 安装 /卸载/升级
    block基本使用和底层
    程序启动 - 类调用的方法
    成员变量修饰词的作用
    宏(define)与常量(const)
    iOS
    监听网络状态
    nil、Nil、NULL与NSNull的区别及应用
  • 原文地址:https://www.cnblogs.com/Extended-Ash/p/9477090.html
Copyright © 2020-2023  润新知