一、關鍵路徑算法
關鍵路徑算法是在工程能完成的情況下找出關鍵的幾個活動,達到工程更早完成的效果。
二、算法分析
這個算法中我們需要用到etv,ltv,ete,lte這幾個變量,還需要用到確保工程能完成的算法,也就是拓撲排序算法
在這個算法中我們把頂點看作是事件,邊權看作是活動持續時間,邊看作是活動
解釋一下這幾個變量的含義,etv,ltv(即事件最早開始時間和時間最晚開始時間)
ete,lte(即活動最早開始時間和活動最晚開始時間)
三、算法步驟
1.利用拓撲排序求出是否能進行關鍵路徑的查詢
2.在拓撲排序的過程中求出事件的最早開始時間
3.利用棧把拓撲序列存儲下來,然后從棧頂依次推出事件的最晚開始時間
4.利用ete和lte判斷這個活動是否是關鍵活動
5.ete等於這個事件的最早開始時間(為什么?因為你這個事件要想發生,必須等前面的事情全部發生完,所以就是最早開始時間的求解步驟)
6.lte等於這個事件的下一個事件的最晚開始時間減去持續時間(為什么?因為下一個事件的最晚開始時間代表着后面的事件能否正常進行,也就是意味着后面的活動是否能進行,同理,最晚活動開始時間也因該是下一個事件的最晚開始時間-持續時間)
四、代碼實現
1 #include "bits/stdc++.h" 2 using namespace std; 3 int etv[110],ltv[110];//etv是事件最早開始事件,ltv是事件最晚開始事件 4 int indegree[110];//記錄某個頂點的入度 5 int u[110],v[110],w[110];//建立鄰接表 6 int first[110],outnext[110]; 7 stack <int> Topo; 8 int n,m; 9 void TopologicalSort()//進行拓撲排序 10 { 11 int cnt = 0; 12 queue <int> ans; 13 for(int i = 1;i <= n;i++) 14 if(!indegree[i])//把入度為0的點放入隊列 15 ans.push(i); 16 while(!ans.empty()){ 17 int v1 = ans.front(); 18 ans.pop(); 19 Topo.push(v1);//把拓撲排序后的序列放入棧,為后面求解最遲事件開始事件做鋪墊 20 cnt++; 21 int k = first[v1];//把他的出邊全部遍歷 22 while(k != -1){ 23 if(!(--indegree[u[k]]))//統計入度為0的點加入拓撲序列 24 ans.push(u[k]); 25 etv[u[k]] = max(etv[u[k]],etv[v1] + w[k]);//求解事件最早開始時間,為什么需要最大值呢?因為你需要保證前面的事件全部都已經結束,所以你這件事只能在前面幾個用時最長的時間做統計 26 k = outnext[k]; 27 } 28 } 29 if(cnt < n)//判斷是否為拓撲序列 30 cout << "Fail" << endl; 31 else 32 cout << "Successful!" << endl; 33 } 34 void CriticalPathMethod() 35 { 36 TopologicalSort();//進行拓撲排序 37 for(int i = 1;i <= n;i++)//因為ltv是求最小值,那么這個數組中的最大也一定是etv中的最大,這樣也不會影響ltv的值的求解 38 ltv[i] = etv[n]; 39 while(!Topo.empty()){//從匯點(終點)往源點(起點)進行求解ltv(最遲開始時間) 40 int v1 = Topo.top(); 41 Topo.pop(); 42 int k = first[v1]; 43 while(k != -1){ 44 ltv[v[k]] = min(ltv[v[k]],ltv[u[k]] - w[k]);//為什么要用min呢?因為你必須得讓后面的活動都能夠按正常時間進行,所以你不能用最大的,不然后面的工程可能會受到影響 45 k = outnext[k]; 46 } 47 } 48 int ete,lte;//ete是活動最早開始時間,lte是活動最晚開始時間。(這里活動指的是邊,而事件指的是頂點) 49 for(int i = 1;i <= n;i++){ 50 int k = first[i]; 51 while(k != -1){ 52 ete = etv[i];//活動最早開始時間就是這之前最長的路徑,所以也就是事件最早開始時間 53 lte = ltv[u[k]] - w[k];//活動最晚開始時間就是不推遲工期的最晚開工時間,也就是出邊的事件的最晚發生時間-這個持續時間(也就是邊權) 54 if(lte == ete)//當最早活動開始時間等於最晚活動開始時間時,這個活動就是關鍵活動,而關鍵活動的全集就是關鍵路徑,關鍵路徑有可能不止一條 55 cout << "(" << i << ',' << u[k] << ')' << ":weight" << w[k] << endl; 56 k = outnext[k]; 57 } 58 } 59 } 60 int main() 61 { 62 cin >> n >> m; 63 for(int i = 1;i <= n;i++) 64 first[i] = -1; 65 for(int i = 1;i <= m;i++){ 66 cin >> v[i] >> u[i] >> w[i]; 67 indegree[u[i]]++;//入度+1 68 outnext[i] = first[v[i]]; 69 first[v[i]] = i; 70 } 71 CriticalPathMethod(); 72 return 0; 73 }
五、測試數據
test case1
6 8
1 2 3
1 3 2
2 5 3
2 4 2
3 6 3
4 6 2
5 6 1
3 4 4
answer1
test case2:
10 13
1 2 3
1 3 4
2 4 5
3 4 8
2 5 6
3 6 7
4 5 3
5 8 4
6 8 6
8 9 5
5 7 9
7 10 2
9 10 3
answer2