51NOD貪心教程(活動安排典型題 詳細解析)

2021-08-21 15:52:15 字數 4661 閱讀 3789

一:

有若干個活動,第i個開始時間和結束時間是[si,fi),只有乙個教室,活動之間不能交疊,求最多安排多少個活動?

分析: 我們就是想提高教室地利用率,盡可能多地安排活動。

考慮容易想到的幾種貪心策略:

(1) 開始最早的活動優先,目標是想盡早結束活動,讓出教室。

然而, 這個顯然不行,因為最早的活動可能很長,影響我們進行後面的活動。例如活動開始和結束時間分別為[0, 100), [1,2) ,[2, 3), [3, 4),[4,5],安排[0,100)的這個活動之後,其他活動無法安排,可是最優解是安排除它外的4個活動。

(2) 短活動優先, 目標也是盡量空出教室。但是不難構造如下反例: [0,5) [5,10) [3, 7), 這裡[3,7)最短,但如果我們安排了[3,7),其它兩個無法安排了。但是最優解顯然是安排其它兩個,而放棄[3,7),可見這個貪心策略也是不行的。

(3) 最少衝突的活動優先, 既然上面安排活動是想減少衝突,那麼如果我們優先安排衝突最少的活動可以麼?至少從(1)和(2)看來,這個策略是有效的。真是對的麼? 嘗試這個例子:

[0,2) [2,4) [4,6) [6,8)

[1,3) [1,3) [1,3) [3,5) [5,7) [5,7) [5,7)

看一下[0,2) 和3個活動衝突——3個[1,3)

[2,4)和4個活動衝突3個[1,3)和乙個[3,5)

[4,6)和也和4個活動衝突3個[5,7)和乙個[3,5)

[6,8)和3個活動衝突——3個[5,7)

下面[1,3)和[5,7)每個都和5個活動衝突,

而[3,5)只和兩個活動衝突——[2,4)和[4,6)。

那按照我們的策略應該先安排[3,5), 可是一旦選擇了[3,5),我們最多隻可能安排3個活動。

但明顯第一行的4個活動都可以安排下來,所以這種策略也是不對的。

(4) 看似最不對的策略——結束時間越早的活動優先。這個策略是有效的,我們可以證明。假設最優解opt中安排了m個活動,我們把這些活動也按照結束時間由小到大排序,顯然是不衝突的。假設排好順序後,這些活動是a(1) , a(2), a(3)….am

假設按照我們的貪心策略,選出的活動自然是按照結束時間排好順序的,並且也都是不衝突的,這些活動是b(1), b(2) …b(n)

問題關鍵是,假設a(1) = b(1), a(2) = b(2)…. a(k) = b(k),但是a(k+1) != b(k+1),回答幾個問題:

(1)b(k+1)會在a(k+2), a(k+3), …. a(m)中出現麼?

不會。因為b(k+1)的結束時間是最早的,即f(b(k+1)) <= f(a(k+1)),而a(k+2), a(k+3), …. a(m)的開始時間和結束時間都在f(a(k+1))之後,所以b(k+1)不在其中。

(2)b(k+1)和a(1), a(2), …. a(k) 衝突麼?

不衝突,因為a(1), a(2), …. a(k)就是b(1), b(2), …. b(k)

(3)b(k+1)和a(k+2), a(k+3), …. a(m)衝突麼?

不衝突,因為f(b(k+1)) <= f(a(k+1)),而a(k+2), a(k+3), …. a(m)的開始時間都在f(a(k+1))之後,更在f(b(k+1))之後。

因此我們可以把a(k+1) 換成b(k+1), 從而最優解和我們貪心得到的解多了乙個相同的,經過乙個乙個替換,我們可以把最優解完全替換成我們貪心策略得到的解。 從而證明了這個貪心策略的最優性。

最後,我們來提供輸入輸出資料,由你來寫一段程式,實現這個演算法。

輸入

第1行:1個數n,線段的數量(2 <= n <= 10000)

第2 - n + 1行:每行2個數,線段的起點和終點(-10^9 <= s,e <= 10^9)

輸出

輸出最多可以選擇的線段數量。
輸入示例

3

1 52 3

3 6

輸出示例

2
**:

#include #include #include #include using namespace std;

const int maxn = 1e4+10;

const int inf = 0x3f3f3f3f;

struct d

}board[maxn];

int main()

sort(board+1,board+1+n);

int sum = 0;

int t = -inf;

for(int i=1 ; i<=n ; ++i)

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

return 0;

}

二:有若干個活動,第i個開始時間和結束時間是[si,fi),活動之間不能交疊,要把活動都安排完,至少需要幾個教室?

分析:能否按照之一問題的解法,每個教室安排盡可能多的活動,即按結束時間排序,再貪心選擇不衝突的活動,安排乙個教室之後,剩餘的活動再分配乙個教室,繼續貪心選擇……

反例: a:[1,2)  b:[1,4) c:[5,6) d:[3,7)

已經按結束時間排好順序,我們會選擇

教室1: a c

教室2:  b

教室3:  d

需要3個教室。

但是如果換一種安排方法,我們可以安排ad在乙個教室,而bc在另外乙個教室,兩個教室就夠了。

所以之前的貪心策略解決不了這個問題。

怎麼辦?之前的策略是用乙個教室找所有它能安排下的活動,即用教室找活動,我們能不能用活動找教室呢?

策略: 按照開始時間排序優先安排活動,如果衝突,則加乙個教室。

簡單地理解一下,策略是這樣,我們把活動按照開始時間有小到大的順序排序。假設目前已經分配了k個教室(顯然k初始等於0),對於當前這個活動,

(1) 如果它能安排在k個教室裡的某乙個,則把它安排在其中的任何乙個教室裡,k不變。

(2) 否則它和每個教室裡的活動都衝突,則增加乙個教室,安排這個活動。

這個策略是最優麼?

我們想像一下k增加1的過程: 因為我們是按照開始時間排序的,意味著當前考慮的這個活動開始的時候,k個教室裡都有活動沒結束(因為如果有乙個教室的活動結束了,我們就可以安排這個活動進入那個教室而不衝突,從而不用增加k)。這就意味著在這個活動開始的時間點,算上目前考慮的這個活動,有(k + 1)個活動正在進行,同一時刻有(k + 1)個活動在進行,無論我們如何安排教室,都至少需要(k + 1)個教室。因為每個教室裡不能同時進行兩個活動。而我們的策略恰好需要(k + 1)個教室,所以是最優的。

這個策略也告訴我們,如果從時間軸上「巨集觀」考慮這個問題。考慮每個時間點同時進行的活動個數,作為這個時間點的厚度(把活動開始和結束時間想像成線段,那麼每個時間點有多少條線段覆蓋它,可以簡單理解為「厚度」),我們至少需要最大厚度那麼多個教室——因為那時恰好有最大厚度那麼多個活動同時進行,而我們這個貪心策略恰好給了我們乙個用最大厚度那麼多個教室安排全部活動的乙個方案。

如果只需要教室的個數,我們可以把所有開始時間和結束時間排序,遇到開始時間就把厚度加1,遇到結束時間就把厚度減1,顯然最初始和最後結束時的厚度是0,在一系列厚度變化的過程中,峰值(最大值)就是最多同時進行的活動數,也是我們至少需要的教室數。

最後,我們來提供輸入輸出資料,由你來寫一段程式,實現這個演算法。

輸入

第一行乙個正整數n (n <= 10000)代表活動的個數。

第二行到第(n + 1)行包含n個開始時間和結束時間。

開始時間嚴格小於結束時間,並且時間都是非負整數,小於1000000000

輸出

一行包含乙個整數表示最少教室的個數。
輸入示例

3

1 23 4

2 9

輸出示例

2
**:

#include #include #include #include using namespace std;

const int maxn = 1e4+10;

struct d

}board[maxn*2];

int re[maxn*2];

int main()

sort(board+1,board+1+n*2);

for(int i=n*2 ; i>0 ; --i)

} for(int i=1 ; i<=n*2 ; ++i)

int ma = 0;

int t = 0;

for(int i=1 ; i<=n*2 ; ++i)

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

return 0;

}

51nod 活動安排問題 (貪心)

有若干個活動,第i個開始時間和結束時間是 si,fi 只有乙個教室,活動之間不能交疊,求最多安排多少個活動?分析 我們就是想提高教室地利用率,盡可能多地安排活動。考慮容易想到的幾種貪心策略 1 開始最早的活動優先,目標是想盡早結束活動,讓出教室。然而,這個顯然不行,因為最早的活動可能很長,影響我們進...

51Nod 活動安排問題(貪心)

有若干個活動,第i個開始時間和結束時間是 si,fi 只有乙個教室,活動之間不能交疊,求最多安排多少個活動?輸入 第1行 1個數n,線段的數量 2 n 10000 第2 n 1行 每行2個數,線段的起點和終點 10 9 s,e 10 9 輸出 輸出最多可以選擇的線段數量。輸入示例 3 1 52 3 ...

活動安排問題 51nod

原題鏈結 問題 有若干個活動,第i個開始時間和結束時間是 si,fi 同乙個教室安排的活動之間不能交疊,求要安排所有活動,最少需要幾個教室?input第一行乙個正整數n n 10000 代表活動的個數。第二行到第 n 1 行包含n個開始時間和結束時間。開始時間嚴格小於結束時間,並且時間都是非負整數,...