POJ1456 Supermarket(贪心+小顶堆)

链接:POJ1456

思路:贪心策略+小顶堆数据结构

思路来源于算法进阶指南,我们的目的是在t的时间内获得更多的利润,该问题可以分解成许多子问题,即每天都卖出商品且保证商品的获利最大。
首先将所有商品按照过期时间从小到大排序;初始化一个空的小顶堆。然后遍历所有商品
1 : 如果当前商品的过期时间大于堆内商品总数,就将该商品直接插入堆内,然后进行调整,(表示着该商品可能在过期时间之前卖出)。
2 : 如果当前商品的过期时间等于堆内商品总数,就将该商品与小顶堆堆顶的节点利润进行比较,如果大于堆顶利润则替换,并向下调整即可。(这表示这在过期时间 t 内有 t 个商品可以卖出,为了尽可能获利, 就将与当前商品利润差最大的替换,即替换小顶堆堆顶替换)。

时空分析:

时间复杂度为 O(NlogN),N为每次商品数。

代码:

#include <iostream>
#include <vector>
#include <algorithm>
#include <string.h>
#include <queue>
#include <stack>
using namespace std;
const int maxn=1e4+10;
int n,pr,da,cur_size;  //n为每次输入的商品数,pr,da暂存每次输入商品利润和过期时间。
struct node{             //cur_size 保存当前堆内商品总数。
    int pi,di;
}x;
vector<node> q,heap;
bool cmp(node a,node b){  //按照过期时间从小到大排序
    return a.di<b.di;
}
void up(int p){  //向上调整
    while(p>1){
        if(heap[p].pi<heap[p/2].pi){
            swap(heap[p],heap[p/2]);
            p/=2;
        }
        else break;
    }
}
void down(int p){ //向下调整
    int s=p*2;
    while(s<=cur_size){
        if(s+1<=cur_size && heap[s].pi > heap[s+1].pi ) s++;
        if(heap[p].pi > heap[s].pi){
            swap(heap[p],heap[s]);
            p=s;s*=2;
        }
        else break;
    }
}
int main(){
    while(scanf("%d",&n)!=EOF){
        x.di=0,x.pi=0;
        heap.clear();
        q.clear();
        heap.push_back(x); //堆下标从1开始,需要给0占位
        cur_size=0;
        for(int i=0;i<n;i++){
            scanf("%d%d",&pr,&da);
            x.pi=pr,x.di=da;
            q.push_back(x);
        }
        sort(q.begin(),q.end(),cmp);
        for(int i=0;i<n;i++){
            if(q[i].di>cur_size){//插入调整
                heap.push_back(q[i]);
                cur_size++;
                up(cur_size);
            }
            else if(q[i].di==cur_size && heap[1].pi<q[i].pi){ //替换调整
                heap[1].pi=q[i].pi;
                heap[1].di=q[i].di;
                down(1);
            }
        }
        int res=0;
        for(int i=1;i<=cur_size;i++){ //最终堆内所有节点利润为总利润
            res+=heap[i].pi;
        }
        cout<<res<<endl;
    }
    
    system("pause");
    return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值