K Best POJ - 3111

最优珠宝选择算法
本文介绍了一种解决特定珠宝选择问题的高效算法。给定n个珠宝,每个有其价值和重量,目标是选出k个珠宝,使总价值与总重量的比例最大化。通过二分查找和快速排序,算法在O(nlog²n)的时间复杂度内找到最优解。

题目大意:给你n个珠宝,每个珠宝有一个价值vivi和重量wiwi,现在要选k个,使得∑vi∑wi∑vi∑wi最大,求这k个珠宝的编号。

解题思路这题和洛谷P1750的题意是一样的,变化的仅是输出的东西和数据范围。此题数据范围是n≤100000n≤100000,所以O(nk)O(nk)的贪心是会超时的。

我们可以二分价值m,如果该价值可用,那么就一定有∑vi∑wi≥m∑vi∑wi≥m,我们把该式变形,得∑(vi−wi×m)≥0∑(vi−wi×m)≥0,于是每次以这个式子为关键字,对所有珠宝进行一次排序,然后判断前k个之和是否≥0≥0即可。时间复杂度O(nlog2n)O(nlog2⁡n)。

#include<cstdio>
#include<algorithm>
#include<cstring>
using namespace std;
#define EPS 1e-9
int n,k;
struct wp{
    int v,w,id;
    double y;
    bool operator <(const wp& rhs)const{return y>rhs.y;}
}a[2000001];
bool ok(double d){
    for(int i=1;i<=n;++i)a[i].y=a[i].v-a[i].w*d;
    sort(a+1,a+n+1);
    double ans=0;
    for(int i=1;i<=k;++i)ans+=a[i].y;
    return ans>=0;
}
int main(){
    scanf("%d%d",&n,&k);
    for(int i=1;i<=n;++i)
    scanf("%d%d",&a[i].v,&a[i].w),a[i].id=i;
    double l=0,r=1e13+1;
    while(r-l>EPS){
        double mid=(l+r)/2;
        if(ok(mid))l=mid;else r=mid;
    }
    for(int i=1;i<=k;++i)printf("%d ",a[i].id);
    printf("\n");
    return 0;
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值