Poj1456 Supermarket(贪心)

题目链接:http://poj.org/problem?id=1456
题意:给定N个商品,每个商品有利润pi和过期时间di,每天只能卖一个商品,过期商品不能再卖,求如何安排每天卖的商品,可以使收益最大

解法一:优先队列+贪心
在最优解中,对于每个时间(天数)t,应该在保证不卖出过期商品的前提之下,尽量卖出利润前t大的商品。我们把商品按照过期时间排序,建立一个初始为空的小根堆,存储商品利润,然后扫描每个商品:
①若当前商品的过期日期等于当前堆中的商品个数,说明此天已经被占用了,就需要进行决策。如果当前商品利润比堆顶利润高,则用此商品替换堆顶商品。说明这个之前有选择的商品没有这个利润更高,而用这个商品来取代它。
②若当前商品过期时间大于堆中商品数,则直接加入就好,因为这个日期并没有被占用
代码如下:

#include<iostream>
#include<cstring>
#include<algorithm>
#include<vector>
#include<queue>
using namespace std;
const int MAXN = 1e4+5;

struct Good{
    int profit;
    int deadline;
}good[MAXN];

int n;


bool cmp(Good g1, Good g2){
    return g1.deadline < g2.deadline;
}
int main()
{
    while(cin >> n)
    {
        priority_queue<int, vector<int>, greater<int> > pq;
        for(int i = 1; i <= n; ++i){
            cin >> good[i].profit >> good[i].deadline;
        }
        sort(good+1, good+1+n, cmp);
        long long ans = 0;
        for(int i = 1; i <= n; ++i){
            if(good[i].deadline == pq.size()){ //t天前已经卖了t个商品,这时如果这个商品更优,则可以替换选中的一个
                if(good[i].profit > pq.top()){
                    pq.pop();
                    pq.push(good[i].profit);
                }
            }
            else if(good[i].deadline > pq.size()){ //t天时还没有卖到t个商品,此天没有被占用,则可以直接选中,不用决策
                pq.push(good[i].profit);
            }
        }
        while(!pq.empty())
        {
            ans += pq.top();
            pq.pop();
        }
        cout << ans << endl;
    }
    return 0;
}

解法二:并查集+贪心
这种解法优先考虑卖出利润大的商品,且对每个商品,在其过期之前尽量晚卖出。这样对于其他商品就有“决策包容性”。

#include<iostream>
#include<cstring>
#include<algorithm>
#include<vector>
using namespace std;
const int MAXN = 1e4+5;

struct Good{
    int profit;
    int deadline;
}good[MAXN];

int pre[MAXN];
int n;

int findFather(int x){
    if(pre[x] == x) return x;
    return pre[x] = findFather(pre[x]);
}
int cmp(Good g1, Good g2){
    return g1.profit > g2.profit;
}
int main()
{
    while(cin >> n)
    {
        for(int i = 0; i < MAXN; ++i)
            pre[i] = i;
        int lim_day = 0;
        for(int i = 1; i <= n; ++i){
            cin >> good[i].profit >> good[i].deadline;
            lim_day = max(lim_day, good[i].deadline);
        }
        sort(good+1, good+1+n, cmp);
        int ans = 0;
        for(int i = 1; i <= n; ++i){
            int day = findFather(good[i].deadline);
            if(day == 0) continue; //安排在第r天卖出
            ans += good[i].profit;
            pre[day] = findFather(day - 1);
        }
        cout << ans << endl;
    }
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值