【關鍵路徑】【拓撲排序+逆拓撲排序】【轉】


https://blog.csdn.net/haskei/article/details/53749380

具體算法描述如下:
1. 輸入e條弧<j,k>,建立AOE-網的存儲結構。
2. 拓撲排序,並求得ve[]。從源點V0出發,令ve[0]=0,按拓撲有序求其余各頂點的最早發生時間ve[i]。如果得到的拓撲有序序列中頂點個數小於網中頂點數n,則說明網中存在環,不能求關鍵路徑,算法終止;否則執行步驟3。
3. 拓撲逆序,求得vl[]。從匯點Vn出發,令vl[n-1] = ve[n-1],按逆拓撲有序求其余各頂點的最遲發生時間vl[i]。
4. 求得關鍵路徑。根據各頂點的ve和vl值,求每條弧s的最早開始時間e(s)和最遲開始時間l(s)。若某條弧滿足條件e(s) = l(s),則為關鍵活動。

為了能按逆序拓撲有序序列的順序計算各個頂點的vl值,需記下在拓撲排序的過程中求得的拓撲有序序列,這就需要在拓撲排序算法中,增設一個棧,以記錄拓撲有序序列,則在計算求得各頂點的ve值之后,從棧頂到棧底便為逆拓撲有序序列。

  1 #include<cstdio>
  2 #include<iostream>
  3 #include<algorithm>
  4 #include<cstring>
  5 #include<string>
  6 #include<cstdlib>
  7 #include<stack> 
  8 
  9 using namespace std;
 10 
 11 typedef long long ll;
 12 const int maxm = 20;
 13 const int maxn = 100;
 14 const int inf = 0x3f3f3f3f;
 15 struct node {
 16     int x, y, w;
 17     int next;
 18 };
 19 node edge[maxm];
 20 int n, m;
 21 int head[maxn];
 22 //e代表活動開始的最早時間, l活動最遲開始的時間, ve[i]事件最早發生的時間, vl[i]事件最遲發生的時間 ,indegree[i]頂點的入度 
 23 //這個地方沒必要分別為e,l開數組了,因為最后只是進行賦值,然后比較兩個數是否相等而已,沒必要開數組了就,不明白可以看下面的代碼 
 24 int e, l, ve[maxn], vl[maxn], indegree[maxn];
 25 stack<int> s, t; //s代表逆序的拓撲排序 ,t代表入度為零的棧,里面存放入度為零的點 
 26 
 27 int TopologicalSort() {
 28     int i, cnt = 0;
 29     for(i=1; i<=n; ++i) //入度為零的點入棧 
 30         if(!indegree[i]) {
 31             t.push(i);
 32             ++cnt;
 33             //printf("%d ", i);
 34         }
 35     while(!t.empty()) {
 36         int a = t.top();
 37         s.push(a);
 38         //printf("%d ", a);
 39         t.pop();
 40         //去掉與入度為零的點的相連的邊,對應的終點的入度減一 
 41         int k = head[a];
 42         while(k != -1) {
 43             if(!--indegree[edge[k].y]) {//終點的度減一后,如果度為零,入棧 
 44                 t.push(edge[k].y);
 45                 ++cnt;
 46                 //printf("%d ", edge[k].y);
 47             }
 48             if(ve[edge[k].y] < ve[a] + edge[k].w) //正拓撲排序求事件發生的最早時間ve[i],到edge[k].y的最長路徑 
 49                 ve[edge[k].y] = ve[a] + edge[k].w;
 50             k = edge[k].next;    
 51         }
 52     }
 53     if(cnt < n) 
 54         return 0;
 55     return 1;
 56 }
 57 
 58 
 59 int main()
 60 {
 61     int i;
 62     memset(head, -1, sizeof(head));
 63     scanf("%d%d", &n, &m);
 64     
 65     //建立鄰接表 
 66     for(i=1; i<=m; ++i) {
 67         scanf("%d%d%d", &edge[i].x, &edge[i].y, &edge[i].w);
 68         ++indegree[edge[i].y];  //終點的入度加一 
 69         edge[i].next = head[edge[i].x];
 70         head[edge[i].x] = i;
 71     }
 72     
 73     if(TopologicalSort() == 0) { //在 TopologicalSort()函數里面已經解決了ve的問題 
 74         printf("不存在關鍵路徑,存在環\n");
 75         return 0;
 76     }
 77     
 78     memset(vl, inf, sizeof(vl));
 79     vl[n] = ve[n]; //最后一個事件的最遲發生事件就等於最早發生時間,因為是最后一件事,也就是說這個工程干完了,以后就沒有事情做了 
 80     while(!s.empty()) { //逆拓撲排序求vl[i] 
 81         int a = s.top();
 82         s.pop();
 83         int k = head[a];
 84         while(k != -1) {
 85             if(vl[a] > vl[edge[k].y] - edge[k].w) {
 86                 vl[a] = vl[edge[k].y] - edge[k].w;
 87             }
 88             k = edge[k].next;
 89         }
 90     }
 91     printf("\n關鍵活動(該活動不能推遲開工)有:\n");
 92     for(i=1; i<=n; ++i)  { 
 93         int k = head[i];
 94         while(k != -1) {
 95             e = ve[i]; //該條邊的起點代表事情,該條邊表示的活動的最早發生時間就等於起點代表的事情的最早發生時間 
 96             //活動的最遲發生時間
 97             l = vl[edge[k].y] - edge[k].w;
 98             if(l == e)
 99                 printf("%d %d %d\n", i, edge[k].y, edge[k].w);
100             k = edge[k].next;
101         }
102     }
103     return 0;
104 }
105 /*
106 9 11
107 1 2 6
108 1 3 4
109 1 4 5
110 2 5 1
111 3 5 1
112 4 6 2
113 5 7 9
114 5 8 7
115 6 8 4
116 7 9 2
117 8 9 4
118 */

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM