算法總結——校門外的樹

問題描述

某校大門外長度爲L的馬路上有一排樹,每兩棵相鄰的樹之間的間隔都是1米。我們可以把馬路看成一個數軸,馬路的一端在數軸0的位置,另一端在L的位置;數軸上的每個整數點,即0,1,2,……,L,都種有一棵樹。 
由於馬路上有一些區域要用來建地鐵。這些區域用它們在數軸上的起始點和終止點表示。已知任一區域的起始點和終止點的座標都是整數,區域之間可能有重合的部分。現在要把這些區域中的樹(包括區域端點處的兩棵樹)移走。你的任務是計算將這些樹都移走後,馬路上還有多少棵樹。 
輸入數據
輸入的第一行有兩個整數L(1 <= L <= 10000)和 M(1 <= M <= 100),L代表馬路的長度,M代表區域的數目,L和M之間用一個空格隔開。接下來的M行每行包含兩個不同的整數,用一個空格隔開,表示一個區域的起始點和終止點的座標。
輸出要求
輸出包括一行,這一行只包含一個整數,表示馬路上剩餘的樹的數目。
輸入樣例
500 3
150 300
100 200
470 471


輸出樣例
298


解題思路

這個問題可以概括爲輸入一個大的整數閉區間,及一些可能互相重疊的在該大區間內的小的整數閉區間。在大的整數閉區間內去除這些小的整數閉區間,問之後剩下的可能不連續的整數區間內有多少個整數。這個題目給出的範圍是大的區間在1~10000以內,要去除的小的區間的個數是100個以內。因爲規模較小,所以可以考慮用空間換時間,用一個大數組來模擬這些區間,數組中的每個數表示區間上的一個數。例如,如果輸入L的長度是500,則據題意可知最初有501棵樹。我們就用一個501個元素的數組來模擬這501棵樹,數組的下標分別代表從1到501棵樹,數組元素的值代表這棵樹是否被一走。最初這些樹都沒有被移走,所以所有數組元素的值都用true來表示。每當輸入一個小區間,就將這個區間對應的樹全部移走,即將這個區間對應的數組元素下標指示的元素的值置成false。如果有多個區間對應同一個數組元素,會導致多次將某個數組元素置成false。不過這並不影響結果的正確性。當所有小區間輸入完成,我們可以數一下剩下的仍舊爲true的元素的個數,就可以得到最後剩下的樹的數目。當然如果最開始輸入的區間不是500,則我們使用的數組大小就不是500。因爲題目給出的上限是10000,所以我們可以定義一個大小是10001個元素的數組,這樣對所有輸入都是夠用的。

參考程序

#include <stdio.h>
void main()
{
    int L, i, j, n; //L爲區間的長度,n爲區間的個數,i和j是循環變量。
    bool trees[10001]; // 用一個布爾數組模擬樹的存在情況。
    for(i = 0; i < 10001; i++) // 賦初值
        trees[i] = true;   
    scanf("%d%d",&L,&n);
    for(i = 0; i < n; i++){
        int begin, end; // 用begin,end存儲區間的起止位置。  
        scanf("%d%d", &begin, &end);
        for(j = begin; j <= end; j++) // 將區間內的樹移走,即賦值爲false。
            trees[j] = false;
    }
    int count = 0; //用count計數,數數剩餘的樹的數目。
    for(i = 0; i <= L; i++)
       if(trees[i])  count ++;
    printf("%d\n", count);
}


實現中常見的問題

問題一:數組開的不夠大,造成數組越界,有的人數組開成trees[10000];
問題二:數組trees沒有初始化,想當然地認爲它會被自動初始化爲0;
問題三:有些人用區間合併的辦法先將要移走樹的小區間合併,但是合併算法想得不清楚;
問題四:循環的邊界沒有等號,少數了一棵樹;
問題五:有人數被移走的樹的數目,然後用L去減它,但是忘記了加一。
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章