頂點活動(activity on vertex,aov)網是指用頂點表示活動,而用邊集表示活動間優先關係的有向圖。例如圖10-57的先導課程示意圖就是aov網,其中圖的頂點表示各項課程,也就是「活動」;有向邊表示課程的先導關係,也就是「活動間的優先關係」。顯然,圖中不應當存在有向環,否則會讓優先關係出現邏輯錯誤。
邊活動(activity on edge,aoe)網是指用帶權的邊集表示活動,而用頂點表示事件的有向圖,其中邊權表示完成活動需要的時間。例如圖10-59中,邊a1~a6表示需要學習的課程,也就是「活動」,邊權表示課程學習需要消耗的時間;頂點v1~v6。表示到此刻為止前面的課程已經學完,後面的課程可以開始學習,也就是「事件」(如v5表示a4計算方法和a3實變函式已經學完,a6泛函分析可以開始學習。從另乙個角度來看,a6只有當a4和a5都完成時才能開始進行,因此當a4計算方法學習完畢後必須等待a5實變函式學習完成後才能進入到a6泛函分析的學習),顯然「事件」僅代表乙個中介狀態。
源點:在aoe網中,沒有入邊的頂點稱為源點;如頂點v1
終點:在aoe網中,沒有出邊的頂點稱為終點;如頂點v6
·只有在進入某頂點的活動都已經結束,該頂點所代表的事件才發生;
·只有在某頂點所代表的事件發生後,從該頂點出發的各活動才開始;
aoe網中的最長路徑被稱為關鍵路徑(強調:關鍵路徑就是aoe網的最長路徑),而把關鍵路徑上的活動稱為關鍵活動,顯然關鍵活動會影響整個工程的進度。
1.事件的最早發生時間ve[k](earliest time of vertex):即頂點vk的最早發生時間。
從源點向終點方向計算
ve[0] = 0
ve[1] = ve[0] + a0 = 0 + 4 = 4
ve[2] = max( ve[0] + a1, ve[1] + a2 ) = max(0 + 3, 4 + 2 = 6
ve[3] = max(ve[1] + a4, ve[2] + a3) = max(4 + 6, 3 + 4) = 10
2.事件的最晚發生時間vl[k](latest time of vertex):即頂點vk的最晚發生時間,也就是每個頂點對應的事件最晚需要開始的時間,超出此時間將會延誤整個工期。
從終點向源點方向計算
vl[3] = ve[3] = 10
vl[2] = vl[3] - a3 = 10 - 4 = 6
vl[1] = min(vl[3] - a4, vl[2] - a2) = min(10-6, 6-2) = 4//之所以求最小,保證其他的點的最晚發生時間
vl[0] = min(vl[2] - a1, vl[1] - a0) = min(4-4, 4-2) = 0
3.活動的最早開工時間e[k](earliest time of edge):即弧ax的最早發生時間。
5條邊,5個活動
e[0] = ve[0] = 0
e[1] = ve[0] = 0
e[2] = ve[1] = 4
e[3] = ve[2] = 6
e[4] = ve[1] = 4
4.活動的最晚開工時間l[k](latest time of edge):即弧ak的最晚發生時間,也就是不推遲工期的最晚開工時間。
e[0] = v[1] - a0 = 4 - 4 = 0
e[1] = vl[2] - a1 = 6 - 3 = 3
e[2] = vl[2] - a2 = 6 - 2 = 4
e[3] = vl[3] - a3 = 10 - 4 = 6
e[4] = vl[3] - a4 = 10 - 6 = 4
活動的最早開始時間和最晚開始時間相等,則說明該活動時屬於關鍵路徑上的活動,即關鍵活動
關鍵路徑演算法是一種典型的動態規劃法,設圖g=(v, e)是個aoe網,結點編號為1,2,...,n,其中結點1與n 分別為始點和終點,ak=∈e是g的乙個活動。演算法關鍵是確定活動的最早發生時間ve[k]和最晚發生時間vl[k],進而獲取頂點的最早開始時間e[k]和最晚開始時間l[k]。
根據前面給出的定義,可推出活動的最早及最晚發生時間的計算方法:
e(k) = ve(i)
l(k) = vl(j) - len(i,j)
結點的最早發生時間的計算,需按拓撲次序遞推:
ve(1) = 0
ve(j) = max
對所有∈e的i 結點的最晚發生時間的計算,需按逆拓撲次序遞推:
vl(n) = ve(n)
vl(i) = min 對所有∈e的j
這種計算方法, 依賴於拓撲排序, 即計算ve( j) 前,應已求得j 的各前趨結點的ve值,而計算vl(i)前,應已求得i的各後繼結點的vl值。ve的計算可在拓撲排序過程中進行,即在每輸出乙個結點i後,在刪除i的每個出邊(即入度減1)的同時,執行
if ( ve[i]+len(i,j)) > ve[j] )
ve[j] = ve[i] + len(i,j)
這時會發現,如果想要獲得ve[j]的正確值,ve[il]~ve[ik]必須已經得到。有什麼辦法能夠在訪問某個結點時保證它的前驅結點都已經訪問完畢呢?沒錯,使用拓撲排序就可以辦到。
當按照拓撲序列計算ve陣列時,總是能保證計算ve[i]的時候ve[il]~ve[ik]都已經得到。但是這時又碰到另乙個問題,通過前驅結點去尋找所有後繼結點很容易,但是通過後繼結點v;去尋找它的前驅結點v1~vx似乎沒有那麼直觀。乙個比較好的辦法是,在拓撲排序訪問到某個結點時,不是讓它去找前驅結點來更新ve[i],而是使用ve[i]去更新其所有後繼結點的ve值。通過這個方法,可以讓拓撲排序訪問到v;的時候,v1~vk一定都已經用來更新過ve[i],此時的ve[i]便是正確值,就可以用它去更新v;的所有後繼結點的ve值。
//拓撲序列
23 stacktoporder;45
//拓撲排序,順便求ve陣列67
bool
topologicalsort()89
4849}50
51if(toporder.size()==n)
5253
return
true;54
55else
5657
return
false;58
59 }
同理,如圖10-64所示,從事件v出發通過相應的活動ar1~ark可以到達k個事件v1~vk,活動的邊權為length[r1]~length[rk]。假設已經算好了事件v1~vk的最遲發生時間xl[j1]~vl[jk],那麼事件vi的最遲發生時間就是vl[j1]-length[r1]~vl[jk]-length[rk]中的最小值。此處取最小值是因為必須保證vj1~vjk的最遲發生時間能被滿足;可以通過下面這個公式輔助理解。
這部分的**如下所示:
v1陣列初始化,初始值為終點的ve值23
//直接使用toporder出棧即為逆拓撲序列,求解v1陣列45
while
(!toporder.empty())67
2627 }
通過上面的步驟已經把求解關鍵活動的過程倒著推導了一遍,下面給出上面過程的步驟總結,即「先求點,再夾邊」:
③e[i-→] = l[i-→i]的活動即為關鍵活動。
主體部分**如下(適用匯點確定且唯一的情況,以n-1號頂點為匯點為例):【主體**】
求取關鍵路徑:
1在上述**中,沒有將活動的最早開始時間e和最遲開始時間l儲存下來,這是因為一般來說e和l只是用來判斷當前活動是否是關鍵活動,沒有必要單獨存下來。如果確實想要將它儲存下來,只需要在結構體node中新增域e和1即可。//遍歷鄰接表的所有邊,計算活動的最早開始時間e和最遲開始時間123
for(int u=0;u)45
2223}24
25return ve[n-1];//
返回關鍵路徑長度
2627 }
如果事先不知道匯點編號,有沒有辦法比較快地獲得關鍵路徑長度呢?當然是有辦法的,那就是取ve陣列的最大值。原因在於,ve陣列的含義是事件的最早開始時間,因此所有事件中ve最大的一定是最後乙個(或多個)事件,也就是匯點。於是只需要在fill函式之前新增一小段語句,然後改變下vl函式初始值即可,**如下:
int maxlength = 0;2
3for(int i=0; ii)45
1213 fill(vl, vl + n, maxlength);
Codeup關鍵路徑 關鍵路徑
時間限制 1 sec 記憶體限制 128 mb 提交 261 解決 90 提交 狀態 討論版 命題人 外部匯入 描述 圖的連線邊上的資料表示其權值,帶權值的圖稱作網。上圖可描述為頂點集為 a,b,c,d,e 邊集及其權值為 始點,終點 權值 a b 3 a c 2 b d 5 c d 7 c e 4...
關鍵路徑法
關鍵路徑法 critical path method,cpm 又稱為要徑法,是計畫專案活動中用到的一種算術方法。1 對於有效的計畫管理而言,關鍵路徑是乙個十分重要的工具。與計畫評核術 project evaluation and reviewtechniqu,pert 非常類似。要徑法所使用的估計作...
關鍵路徑法
aoe網 在乙個表示工程的帶權有向圖中,用頂點表示事件,用有向邊表示活動,邊上的權值表示活動的持續時間,稱這樣的有向圖叫做邊表示活動的網,簡稱aoe網。aoe網中沒有入邊的頂點稱為始點 或源點 沒有出邊的頂點稱為終點 或匯點 aoe網的性質 只有在某頂點所代表的事件發生後,從該頂點出發的各活動才能開...