1. 程式人生 > >POJ1456貪心(set或者並查集區間合併)

POJ1456貪心(set或者並查集區間合併)

題意:
      給你n商品,每個商品有自己的價值還有保質期,一天最多隻能賣出去一個商品,問最大收益是多少?


思路:
      比較好想的貪心,思路是這樣,每一次我們肯定拿價值最大的,至於在那天拿當然是儘可能的往後拖了,因為可以把前面的時間留給一些快過期的用,這種貪心策略很容易想到,對於實現的時候我嘗試了兩種方法,首先把商品按照價格從大到小排序,一個是我以前常用的set容器,他可以直接取出一個大於等於x的最小值(只要加上符號功能就是取最小的最大了),先把所有的天數都當成資源放進set裡,然後對於沒一個物品,如果可以買的話,那麼就消耗離他保質期最近的那個沒有備用的天,這樣就行了,總的時間複雜度應該是O(n*log(n))的,可以接受,第二個方法我是用的並查集來處理區間合併,思路都是一樣,就是在處理資源(天)的時候用並查集優化時間,比如一開始一個區間 1 2 3 4當第3天用了之後那麼第三天就和第2天合併算一天了 1 2 4,就是這樣每個天數的祖宗存的就是他左側第一個沒有用過的天數。這樣寫的話,如果用上路徑壓縮時間複雜度是O(n)的,比set快不少,如果不用路徑壓縮時間在邏輯上是O(n*n)的,但是剛剛我測試了下,跑了200+ac了。哎!這不重要。呵呵。




並查集+貪心 79ms
#include<stdio.h>
#include<algorithm>


#define N 10000 + 10


using namespace std;


typedef struct
{
    int p ,d;
}NODE;


NODE node[N];
int mer[N];


bool camp(NODE a ,NODE b)
{
    return a.p > b.p;
}


int finds(int x)
{
    return x == mer[x] ? x : mer[x] = finds(mer[x]);
}


int main ()
{
    int n ,ans ,i ,max;
    while(~scanf("%d" ,&n))
    {
        max = 0;
        for(i = 1 ;i <= n ;i ++)
        {
            scanf("%d %d" ,&node[i].p ,&node[i].d);
            if(max < node[i].d) max = node[i].d;
        }
        for(i = 0 ;i <= max ;i ++)
        mer[i] = i;
        ans = 0;
        sort(node + 1 ,node + n + 1 ,camp);
        for(i = 1 ;i <= n ;i ++)
        {
            int x = finds(node[i].d);
            if(!x) continue;
            int y = finds(x-1);
            mer[x] = y;
            ans += node[i].p;
        }
        printf("%d\n" ,ans);
    }
    return 0;
}














set+貪心 474ms
#include<set>
#include<stdio.h>
#include<algorithm>


#define N 10000 + 10


using namespace std;


typedef struct
{
    int p ,d;
}NODE;


NODE node[N];
set<int>myset;


bool camp(NODE a ,NODE b)
{
    return a.p > b.p;
}


int main ()
{
    int n ,i;
    while(~scanf("%d" ,&n))
    {
        int max = 0;
        for(i = 1 ;i <= n ;i ++)
        {
            scanf("%d %d" ,&node[i].p ,&node[i].d);
            if(max < node[i].d) max = node[i].d;
        }
        myset.clear();
        myset.insert(0);
        for(i = 1 ;i <= max ;i ++)
        myset.insert(-i);
        sort(node + 1 ,node + n + 1 ,camp);
        int ans = 0;
        for(i = 1 ;i <= n ;i ++)
        {
            int x = *myset.lower_bound(-node[i].d);
            if(!x) continue;
            ans += node[i].p;
            myset.erase(x);
        }
        printf("%d\n" ,ans);
    }
    return 0;
}