并查集的一般操作 ④
RT
并查集一般操作最后一篇
原题 POJ1456
翻译:
给定N个商品,每个商品有利润Pi和过期时间di,每天只能卖一个商品,过期商品不能在卖,求如何安排每天买的商品,可以使收益最大。1≤N,pi,di≤10000.
发现,好像可以用贪心的想,从先要过期的商品中卖出利润大的;
就可以按时间排个序,然后依次按价格放入二叉堆中,每次用大的替换利润低的;
可以,不过这次想用另一种贪心策略。
我先卖利润大的商品,并且尽可能晚地卖出;
哦?... interesting!
然后
我们就可以按利润排序,然后建立一个关于天数的并查集;
什么意思?就这个意思:
对于每个商品,若它在d天只有过期,就在并查集中查询d的根R,若R大于0,则安排在第R天卖出,然后把R并到R-1上(还是不懂可以手动模拟)
多思考。
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
#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; } }
11:34:22 2018-02-07