你一定看得懂的關鍵路徑概念
原文地址:你一定看得懂的關鍵路徑概念 - 知乎 (zhihu.com)
在學習資料結構的過程中,我發現關鍵路徑的中的概念取名使得第一印象讓人容易產生誤解,所以我用最通俗易懂的例子來解釋解釋這些概念的實際含義。
基本概念——AOE網
有幾個最基本的概念我們要先了解,在帶權有向圖中,頂點表示事件,有向邊表示活動,以邊上的權值表示活動的開銷,比如完成活動所需要的時間。這樣的網路稱為用邊表示活動的網路,也就是AOE網。
分清發生和開始
這裡要首先弄明白的是兩個詞,也就是後面要學到的概念中的 "發生" 和 "開始"。
“發生”是針對於事件的,也就是圖中的頂點。什麼叫事件發生了呢?
只有在指向該頂點的所有有向邊對應的活動結束,該頂點所代表的事件才發生。
舉個例子,一個事件C,它僅被兩條邊a, b指向,僅當a,b兩活動都完成時,事件C發生。
“開始”是針對於活動的,也就是圖中的邊。
只有在一個頂點所代表的事件發生後,從該頂點出發的所有邊對應的活動才能開始。
什麼時候開始?即可以在事件一完成就立馬開始接下來的活動,也可以推遲活動開始的時間。
最早發生時間——VE
到這裡就已經能解釋我們要說的第一個概念了,最早發生時間。
我猜這裡應該經常會有人有疑惑,為什麼是最長的路徑長度決定最早的發生時間?我越想要早發生不是越應該走短的路徑嗎?
且聽我說,擺脫困惑的重點是我們要和求最短路徑的思路區分開,求最短路徑是找儘可能短的路來保證路徑長度最小,你只需要找出一條最短的路就行。但是在關鍵路徑裡,一個頂點是有多個前提的,只有前提的路徑都走完,才能發生該頂點的事件,那麼只有最長的路徑走完,保證其餘短的路都早已經走完,該事件才發生。
我們前面說過,發生是針對於事件的,一個事件要發生,首先要指向它的活動都完成。一個事件C,被兩個活動a,b指向,a活動的耗費時間是3, b活動的耗費時間是5。那麼看下圖,從開始到C事件的發生要多久呢?
是最大路徑長度5,因為C事件發生的前提必須是a,b兩活動完成(活動可同時進行),C事件只有等到b完成才發生,最早完成時間由耗時最久的路決定,所以這就是為什麼要取最長路徑長度。
所以求目標頂點最早發生時間的方法是:
目標頂點的所有前提頂點(比如上圖中C的前提頂點為A頂點和B頂點)的最早完成時間+對應的前提頂點到目標頂點的活動消耗 中的最大值。
比如C的最早完成時間是: Max{ A的最早完成時間+A到C的活動消耗時間, B的最早完成時間+B到C的活動消耗時間}
具體遞推公式:
- ve(源點)=0
- ve(k) = Max{ ve{j} + Weight(j, k) }, j為k的任意前提頂點, Weight(j, k)表示<j, k>上的權值 。
只要從源點開始一直遞推到匯點(終點)就好了。
最遲發生時間——VL
最遲發生時間的定義是這樣的:在不推遲整個工程完成的前提下,保證後繼事件j能在其最遲發生時間vl(j)能夠發生時,該事件最遲必須發生的時間。
嚯!好傢伙,自己的定義裡套著自己,這一波套娃是真存心不想讓人看懂。
首先,我們要知道,匯點的最遲發生時間就是它的最早發生時間(可以理解為匯點的最早發生時間就是工期),求VL的過程我們是從匯點倒著推回去的。
其次,為什麼會有最遲發生時間呢?這是因為一個工程中,通常會存在某條路徑耗時比其他路徑久的多,所以耗時短的事件可以不必太早發生,也就是存在著緩衝時間。
為了方便理解,我舉一個數據大小相差較大的例子:
看看這個圖,我在頂點上方寫了它的最早發生時間,D是匯點,110是它的最早發生時間(也是最遲發生時間)。
此時我們可以這樣理解,如果在110天時工程必須完成,那麼A事件最遲什麼時候要發生?
我們可以用110減去a活動用時,得到105,也就是說A事件最遲可以在第105天發生(一旦發生就要立刻開始a活動,否則將推遲整個工期),指向A的活動可以在第100天才開始。
而A事件最早可以在第5天就發生(這裡說最早才有意義了),最早第5天完成,但是可以推遲到第105天完成,中間差了100天了。
同理可得B事件的最遲發生時間是第10天,它一刻也不能拖。
這時候再回去看看最遲發生時間的定義,應該就可以理解了吧
再剛剛舉的例子裡,AB事件是相互獨立的,如果我再新增一個不獨立的事件:
這個圖中我添加了一個C頂點,它是B頂點的前提。我把已知的最遲發生時間用綠色筆跡寫在了最早發生時間右邊。一起看看C事件的最遲發生時間是多少吧。
這裡我們可以看到,和上圖不同,C頂點有2個出度,也就意味著它影響著兩個後繼頂點。
如果我們仍用上次的方法,用110-10得100,可以認為C事件最遲在第100天發生嗎?
仔細看看是不對的,B頂點的發生前提是C頂點要發生,如果C在第100天才發生,那麼B事件等不了啊,B最遲在第10天就要發生,等到第100天干脆毀滅吧
正確的做法應該是B事件的最遲發生時間減4天得第6天。由此可見,一個頂點的最遲發生時間其實是由它的後繼節點所決定的,這也就解答了為什麼我們要從匯點開始倒著往起點推。
我想你也可以理解了為什麼公式中使用的是 Min{} 取最小。就比如剛剛的例子,C有兩個選擇——第6天或者第100天,你必須得選最小的以保證你不會耽誤任何後繼節點的最遲發生。
遞推公式:
vl(匯點) = ve(匯點)
vl(k) = Min{ vl(j) - Weight(k, j) } ,k為j的任意前驅
活動的最早開始時間——e和最遲開始時間——l
這兩個概念相比之前的就簡單多了,首先,還記得我在一開始說的嗎,“開始”是針對活動,也就是圖中的邊的概念。
活動的最早開始時間,理解起來非常容易,邊的起點事件一旦發生就立刻開始,就是最早開始時間了。
公式:若邊<k, j> 表示活動i,則有e(i) = ve(k)
那最遲開始時間呢,這要和該邊指向事件的最遲發生時間掛鉤,假如在10點必須寫完作業(事件),寫作業(活動)要2小時,那最晚啥時候開始寫作業呢?8點對吧,也就是邊所指向的事件最晚發生時間-邊對應的活動所需時間。
公式: 若邊<k, j> 表示活動i,則有l(i) = vl(j) - Weight(k,j)
時間餘量d
d(i) = l(i) - e(i),即活動最遲開始時間與最早開始時間的差額,這代表著活動可以拖延的時間。如果一個活動的時間餘量為0,就意味著該活動不能拖延時間,稱為關鍵活動,必須立即完成,否則就將拖延整個工期。
而時間餘量為0的所有邊連起來,就是關鍵路徑了。
要求時間餘量d, 就要先求活動的最早開始時間e和最遲開始時間l,要求e和l就要先求事件最早發生時間ve和最遲發生時間vl。所以做題步驟就出來啦,最後來做一題試試看吧!
答案:
最終得到的關鍵路徑為(v1, v3, v4, v6)
最後注意的幾點:
- 關鍵路徑上的所有活動都是關鍵活動, 它是決定整個工程的關鍵因素,因此可以通過加快關鍵活動來縮短整個工期。但是也不能任意縮短,因為一旦縮短到一定的程度,該關鍵活動就可能變成非關鍵活動了
- 網中的關鍵路徑不唯一,對於有好幾條關鍵路徑的網,只加快其中某一條關鍵路徑上的活動並不能縮短工期。只有加快存在於所有關鍵路徑上的關鍵活動才能達到縮短工期的目的。