并查集的一般操作 ④

RT

并查集一般操作最后一篇

原题 POJ1456

翻译:

 给定N个商品,每个商品有利润Pi和过期时间di,每天只能卖一个商品,过期商品不能在卖,求如何安排每天买的商品,可以使收益最大。1≤N,pi,di≤10000.

发现,好像可以用贪心的想,从先要过期的商品中卖出利润大的;

就可以按时间排个序,然后依次按价格放入二叉堆中,每次用大的替换利润低的;

可以,不过这次想用另一种贪心策略。

我先卖利润大的商品,并且尽可能晚地卖出;

哦?...       interesting!

然后

我们就可以按利润排序,然后建立一个关于天数的并查集;

什么意思?就这个意思:

对于每个商品,若它在d天只有过期,就在并查集中查询d的根R,若R大于0,则安排在第R天卖出,然后把R并到R-1上(还是不懂可以手动模拟)

多思考。

#include <cstdio>
#include <algorithm>

using namespace std;

struct b
{
    int fa[10010];
    inline void be(int n){for(int i=0;i<=n;++i)fa[i]=i;return;}
    int f(int x){return fa[x]=fa[x]==x?x:f(fa[x]);}
    int u(int x,int y){return fa[f(y)]=f(x)-1;}    //把R并到R-1上
}a;
int n;
struct d
{
    int day,val;
    friend bool operator < (d a,d b)
    {
        return a.val > b.val;
    }
}num[10010];
int ans;
int main()
{
   // freopen("in","r",stdin);
    while(scanf("%d",&n)==1)
    {
        a.be(10005);
        for(int i=0;i<n;++i)
        {
            scanf("%d%d",&num[i].val,&num[i].day);
        }
        sort(num,num+n);         //按利润排序
        for(int i=0;i<n;++i)
        {
            int root=a.f(num[i].day);
            if(root>0)                          //如果有时间就卖
            {
                //printf("%d\n",a.f(num[i].day));
                a.u(num[i].day,num[i].day);
                ans+=num[i].val;
            }
        }
        printf("%d\n",ans);
        ans=0;
    }
}    
View Code

                                                                    11:34:22 2018-02-07

原文地址:https://www.cnblogs.com/AidenPearce/p/8425844.html