poj-1456 并查集作链表

poj-1456 并查集作链表

题意:

超市里有N个商品. 第i个商品必须在保质期(第di天)之前卖掉, 若卖掉可让超市获得pi的利润. 每天只能卖一个商品. 现在你要让超市获得最大的利润.

题解

测试样例:

样例来源 :​🙅​:🙅‍♂​

// in.text
0

4 
50 2  10 1  20 2  30 1

4 
50 2  10 1  15 2  27 1 

5 
1 3  15 2   5 3  20 2  10 1

7 
20 1  2 1  10 3 100 2 8 2 5 20  50 10

10
13 2 18 1 68 10 72 8 11 7 41 2 48 7 15 7 34 1  13 8
//ou.text
0
80
77
40
185
302

错误的思路:

把商品先按照期限由小到大排,再按利润由大到小排,用此排序规则的结构体放到优先队列里去。

错误原因是可能有的期限很晚,但是价值很高。

比如这个样例

5   1 3  15 2   5 3  20 2  10 1

如果按这个错误的思路,那么就是 10+20+5=35

而答案应该是 20+15+5

ac思路:

<一> 用优先队列

🐤 从后面往前面数,

for(int i=m;i>=1;–i) 如果从i这个时刻还有事情能被做,就加入到那个挑选的优先队列中去。

#include "cstdio"
#include "cstring"
#include "algorithm"
#include "queue"
using namespace std;
const int maxn=1e4+10;
struct  re
{
    int use,p,d;
    re (int a=0,int b=0)
    {
        p=a;d=b;
    }
};
bool cmp1(const re &a,const re& b)
{
    return a.d<b.d;
}
struct cmp {
    bool operator() (const re &a, const re &b) const {
        return a.p < b.p;
    }
};
re all[maxn];
priority_queue<re,vector<re>,cmp > have;
int main()
{
//    freopen("in.text","r",stdin);
    int n;
    while (scanf("%d",&n)!=EOF)
    {
        int big=0;
        for(int i=1;i<=n;++i) {
            scanf("%d %d", &all[i].p, &all[i].d);
            big=max(all[i].d,big);
        }
        sort(all+1,all+1+n,cmp1);

        int d=n,ans=0;

        while (!have.empty())have.pop();
        for(int i=big;i>=1;--i)
        {
            for(;d>=1;--d)
            {
                if(all[d].d>=i)have.push(all[d]);
                else break;
            }
            if(!have.empty()) {
                ans += have.top().p;
                have.pop();
            }
            }
        printf("%d\n",ans);
    }
    return  0;
}
<二>用并查集

把所有的按利润排列好,这个事情只能在那个时间之前做完,假设都在那个时间做,而那个时间已经做了其他事情,那就只能在那个时间之前做了。显然,这是链表的使用(如果当前被用完了,就前进一个),这是不是就像当前被用完了,就用父亲一样,因此可以用并查集代替链表🌟。

#include "cstdio"
#include "cstring"
#include "algorithm"
#include "queue"
using namespace std;
const int maxn=1e4+10;
struct  re
{
    int p,d;
};
bool cmp1(const re &a,const re& b)
{
    return a.p>b.p;
}
int fa[maxn];
int anc(int a)
{
    if(fa[a]==-1)return a;
    return fa[a]=anc(fa[a]);
}

re all[maxn];
int main()
{
//    freopen("in.text","r",stdin);
    int n;
    while (scanf("%d",&n)!=EOF)
    {
        memset(fa,-1, sizeof(fa));
        for(int i=1;i<=n;++i) {
            scanf("%d %d", &all[i].p, &all[i].d);
        }
        sort(all+1,all+1+n,cmp1);

        int ans=0;
        for(int i=1;i<=n;++i)
        {
            int get=anc(all[i].d);
            if(get>0)
            {
                ans+=all[i].p;
                fa[get]=get-1;
            }

        }
        printf("%d\n",ans);
    }
    return  0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

是Mally呀!

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值