【贪心】兔警官朱迪买礼物

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/qq_37636528/article/details/57456170

传送门:https://vijos.org/d/jcsy/p/58b2b8bad3d8a123ab08db9f
这是一道贪心题,主要由2部分组成
1、首先最优情况必定是k张优惠券全部用完,那么先按优惠价排序,排出来前k个优惠价之和如果比m大,则从小到大按优惠价能买几个买几个,然后输出
2、然后考虑如果步骤1后前k个都买下并还有钱剩余,则可能可以再多买,

但是:

前k个必定不能扔掉:一旦某个被扔掉,则只能省下1张优惠券,这张优惠券用于新的物品要花的钱必定比留下那个扔掉的要多
所以要加入新的只有两种可能:
(1)从已有的取出一张优惠券用于加入新的物品(此时新的优惠价要最小,并且被取出优惠券的物品优惠价与原价之差要最小)
(2)用原价加入新的物品(此时新的原价要最小)
从(1)(2)中取较优状态用于加入
那么为了维护已加入物品优惠价与原价之差最小,可以用堆

以下代码

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<queue>
using namespace std;

#define MAX 100000000000000007
#define LL long long

priority_queue< LL,vector<LL>,greater<LL> > h;
LL n,m,k,s,a_xb,b_xb,ans;
bool f[100005];

struct price{
    LL x,y,z;
    bool operator <(const price &s)const{
        return y<s.y;
    }
}
a[100005],b[100005];

bool cmp(struct price x,struct price y){
    return x.x<y.x;
}

int main(){
    cin>>n>>m>>k;
    for (int i=1;i<=n;i++){
        cin>>a[i].x>>a[i].y;
        a[i].z=i;
    }
    sort(a+1,a+n+1);

    for (int i=1;i<=m;i++){
        if (s+a[i].y<=k){
            s+=a[i].y;
            h.push(a[i].x-a[i].y);
        }
        else{
            cout<<i-1;
            return 0;
        }
    }

    memcpy(b,a,sizeof b); sort(b+m+1,b+n+1,cmp);
    a_xb=m+1; b_xb=m+1;
    a[n+1].x=a[n+1].y=MAX; b[n+1].x=b[n+1].y=MAX;
    ans=m;
    while (a_xb<=n||b_xb<=n){
        if (a[a_xb].y+h.top()<b[b_xb].x){
            s+=a[a_xb].y+h.top();
            h.pop();
            h.push(a[a_xb].x-a[a_xb].y);
            f[a[a_xb].z]=1;
        }
        else{
            s+=b[b_xb].x;
            f[b[b_xb].z]=1;
        }
        if (s>k){
            cout<<ans;
            return 0;
        }
        else ans++;
        while (f[a[a_xb].z]&&a_xb<=n) a_xb++;
        while (f[b[b_xb].z]&&b_xb<=n) b_xb++;
    }
    cout<<ans;
    return 0;
}

展开阅读全文

没有更多推荐了,返回首页