1. 程式人生 > >並查集的一般操作 ④

並查集的一般操作 ④

利潤 分享圖片 gpo 不能 poj hid return %d mes

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

並查集的一般操作 ④