1. 程式人生 > >ACM知識點 之 貪心(3)區間選點問題

ACM知識點 之 貪心(3)區間選點問題

區間選點的問題大致可以描述為: 
給定N個區間[a,b],取儘量少的點,使得每個區間內都至少有一個點(不同區間內含的點可以重複)。

關於貪心演算法的驗證過程就不再贅述,現在思考一下貪心策略的制定。 
對於區間[a1, b1] 、[a2, b2]、 [a3, b3] 來說, 
如果想選擇最少的點,那麼必須選擇每個區間的右端點,示意圖如下: 
示意圖

當你每一次都選擇區間的最右端,才能保證每一個選的點覆蓋的範圍都是最廣泛的,也就是說選的點才是最少的。

和之前不相交區間的思考方法類似,把區間進行預處理,按照端點的大小排序(同樣,按照右端點排序會好理解一點,但是左端點排序一樣可以起到作用,初學者不必迷信右端點排序)。 
預處理過後,求解策略的思路和求不相交區間相似,如果下一個區間的左端點不被覆蓋,則答案+1,如下:

while(剩餘區間的數目不為0)
{
    if(找到符合條件的下一個區間)
    {
        當前區間 = 下一個區間;
        答案數+1;
    }

    區間數--;
}
                                    非洲小孩
                    時間限制:1000 ms  |  記憶體限制:65535 KB
                                    難度:2

描述 
家住非洲的小孩,都很黑。為什麼呢? 
第一,他們地處熱帶,太陽輻射嚴重。 
第二,他們不經常洗澡。(常年缺水,怎麼洗澡。) 
現在,在一個非洲部落裡,他們只有一個地方洗澡,並且,洗澡時間很短,瞬間有木有!!(這也是沒有的辦法,缺水啊!!) 
每個小孩有一個時間段能夠洗澡。並且,他們是可以一起洗的(不管你是男孩是女孩)。 
那麼,什麼時間洗澡,誰應該來洗,由誰決定的呢?那必然是他們偉大的“澡”神啊。“澡”神有一個時間表,記錄著該部落的小孩,什麼時候段可以洗澡。現在,“澡”神要問你,一天內,他需要最少開啟和關閉多少次洗澡的水龍頭呢?因為,開啟和關閉一次水龍頭是非常的費力氣的,即便,這也是瞬間完成的。

輸入 
多組資料 
第一行一個n<=100。 
接下來n行,每行一個時間段。H1H1:M1M1-H2H2:M2M2,24小時制。 
保證該時間段是在一天之內的。但是,不保證,H1H1:M1M1先於H2H2:M2M2。

輸出 
題目描述,“澡”神最少需要開啟和關閉多少次水龍頭呢?

樣例輸入 

00:12-12:12 

00:12-12:12 
14:00-12:00

樣例輸出 

1

提示 
Ps:開啟和關閉為一次

這道題是完美的區間選點,但是資料有坑(不保證H1H1:M1M1先於H2H2:M2M2。) 所以讀入的時候要注意進行判斷。

解決程式碼如下:

/*
************************************
    Title: NYOJ1036-非洲小孩
************************************
    Date:2015/07/23
************************************
    author:劉旭
************************************
Memory:256KB
Time:8ms
************************************
*/
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;

#define MAX 1005

struct Node
{
    int x;
    int y;
};

Node map[MAX];

bool cmp(Node a,Node b){
    if(a.y != b.y){
        return a.y < b.y;
    }

    return a.x < b.x;
}

int main()
{
    int num = 0;
    while(EOF != scanf("%d", &num)){
            memset(map, -1, sizeof(map));
            int a1,b1,a2,b2;

            for(int i = 0; i < num; i++){
                scanf("%d:%d-%d:%d",&a1,&b1,&a2,&b2);
                int key1 = a1*60+b1;
                int key2 = a2*60+b2;
                if(key1 > key2){
                    swap(key1, key2);
                }
                map[i].x = key1;
                map[i].y = key2;
            }

            sort(map, map+num, cmp);

            int start = map[0].y;
            int num_node = 0;
            int ans = 1;
            while(num - num_node){
                if(map[num_node].x > start){
                    start = map[num_node].y;
                    ans++;
                }

                num_node++;
            }

            printf("%d\n", ans);
    }

    return 0;
}