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);
}

转载于:https://www.cnblogs.com/Extended-Ash/p/9477090.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值