(超市)贪心+并查集(并查集染色问题)

这种类型的题类似与并查集区间染色,这个题指的是pre[i]指的是祖先第一个没有染色的点

这个一开始初始化为-1,

 

题目:poj1456

题意: 给定N个商品,每个商品有利润pi和过期时间di,每天只能买一个商品,过期不能再卖,求如何安排每天卖出的商品,可以使得收益最大。
数据范围:1<N,pi,di<10^4.

思路:
1)首先不难想到贪心先卖出价值最大的商品,先用按照价值从大到小sort排序。
2)我们贪心选择在其过期的前一天(day-1)卖出,然后如何维护卖出一天后另外其他的商品不能再在同一天卖出,先思考两个价值不一样的商品u,v,u.p>v.p,但保质期都是同一天day,那么u安排在day-1出售,v再出售时候发现day-1已经出售过,那么我们往前递推day-2出售,这样递归往前的出售商品,如果递归到最后day‘=0那么显然不可以再出售类似并查集的思想维护即可。

看到这个题目之后,排序还是要排的,就是按照价值从大到小排序,排完序之后就遍历数组,如果不用并查集维护的话,就是

对于这一天di,遍历di到1看看没有用到这一天就标记上,但是这样会超时。

如果用并查集的话,就有一个路径压缩,会很省时间(就是假如说6,5,4标记了,pre[6]会标记成3这样查找的时候直接找到3,会节省大大时间的

#include<iostream>
#include<algorithm>
#include<cstring> 
typedef long long ll;
using namespace std;
const int maxn=1e5+100;
int pre[maxn];
struct node{
    ll w;
    ll t;
}a[maxn];
bool cmp(node x,node y){
    return x.w>y.w;
}
int find(int x){
    if(pre[x]==-1){
        return x;
    }    
    else{
        return pre[x]=find(pre[x]);
    }
}
int main(){
    int n;
    while(cin>>n){
        for(int i=1;i<=n;i++){
            scanf("%d%d",&a[i].w,&a[i].t);
        } 
        memset(pre,-1,sizeof(pre));
        sort(a+1,a+n+1,cmp);
        ll ans=0;
        for(int i=1;i<=n;i++){
            int p=find(a[i].t); 
            if(p>0){
                ans+=a[i].w;
                pre[p]=p-1;
            }
        }
        cout<<ans<<endl;
    }
} 

 

posted @ 2021-01-13 22:32  哎呦哎(iui)  阅读(100)  评论(0编辑  收藏  举报