[POJ 1456]Supermarket[贪心][优先队列or并查集优化]

本文针对POJ1456超市问题提供了一种贪心算法解决方案,并介绍了如何利用优先队列和并查集优化算法实现。通过对比两种方法的实现代码,展示了并查集在该问题中的应用技巧。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

题目链接:[POJ 1456]Supermarket[贪心][优先队列or并查集优化]

题意分析:

给出若干个商品,每个都有自己的销售截至日期,每天只能销售一个,每销售一个都能得到钱,问:最多能挣到多少钱?

解题思路:

这里可以使用贪心的思路。从末尾往前面数日期,如果当天有商品截止,就把这些商品全都放入优先队列,然后卖出价值最大的那一个;如果当天没有商品截止,就去卖优先队列里价值最大的那个。具体证明大概就是:每天可以决策的商品都是可达的,既然为了最总利润最大,那么就卖出最大的。(嗯,很是勉强的证明啊XD)。

最后说说并查集优化:首先还是对商品按价值进行排序,每次取出价值最大的商品,判断是否能有日期能够给其卖出去,每次默认用最大的日期去卖,如果这个日期已经被使用了,就向前挪一天,直到不能挪,那这个商品就不卖了。

个人感受:

虽说是并查集专题,真心不知道哪里能用并查集。然后就给贪心过了。96MS。然后上网查查,哇,还真能用并查集,原来是优化,有了贪心的思路,整个并查集也好理解了,并查集还能这么用ORZ。

具体代码如下:

优先队列君(94ms):

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

const int MAXN = 1e4 + 111;

vector<int> v[MAXN]; // 存一下这一天都有什么商品截止了

int main()
{
    int n, p, d, up;
    while (~scanf("%d", &n))
    {
        up = 0;
        for (int i = 1; i <= 1e4 + 11; ++i) v[i].clear();
        for (int i = 0; i < n; ++i)
        {
            scanf("%d%d", &p, &d);
            up = max(up, d);
            v[d].push_back(p);
        }
        int ans = 0;
        vector<int>::iterator it;
        priority_queue<int> pq;
        for (int i = up; i >= 1; --i)
        {
            if (v[i].size())
            {
                for (it = v[i].begin(); it != v[i].end(); ++it) // 将所有商品放入优先队列
                    pq.push(*it);
                ans += pq.top();
                pq.pop();
            }
            else if (pq.size())
            {
                ans += pq.top();
                pq.pop();
            }
        }
        printf("%d\n", ans);
    }
    return 0;
}

并查集优化(63ms):

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

const int MAXN = 1e4 + 111;

int p[MAXN];
struct N{
    int p, d;
    bool operator < (const N& t)const
    {
        return p > t.p;
    }
}a[MAXN];

int find(int x)
{
    return p[x] == x ? x : p[x] = find(p[x]);
}

int main()
{
    int n;
    while (~scanf("%d", &n))
    {
        int ans = 0;
        for (int i = 0; i <= 1e4 + 11; ++i) p[i] = i;
        for (int i = 0; i < n; ++i)
        {
            scanf("%d%d", &a[i].p, &a[i].d);
        }
        sort(a, a + n);
        for (int i = 0; i < n; ++i)
        {
            int temp = find(a[i].d); // 查找可用的日子
            if (temp > 0)
            {
                p[temp] = temp - 1; // 使用之后将日期向前挪
                ans += a[i].p;
            }
        }
        printf("%d\n", ans);
    }
    return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值