(超市)贪心+并查集(并查集染色问题)
这种类型的题类似与并查集区间染色,这个题指的是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; } }