1. 程式人生 > >數據結構 計算關鍵路徑

數據結構 計算關鍵路徑

blank pan 關鍵活動 nbsp https print clas 工程 style

  如果在有向無環圖中用有向邊表示一個工程中的各項活動(Activity),用有向邊上的權值表示活動的持續時間(duration),用頂點表示事件(Event),則這種有向圖叫做用邊表示活動的網絡(activity on edges),簡稱AOE網絡。例如:

  技術分享

  其中,Ei表示事件,ak表示活動。E0是源點,E8是匯點。

  完成整個工程所需的時間等於從源點到匯點的最長路徑長度,即該路徑中所有活動的持續時間之和最大。這條路徑稱為關鍵路徑(critical path)。關鍵路徑上所有活動都是關鍵活動。所謂關鍵活動(critical activity),是不按期完成會影響整個工程進度的活動。只要找到關鍵活動,就可以找到關鍵路徑。

  與計算關鍵活動有關的量:

  1 事件Ei的最早可能開始時間:Ee[i]—從源點E0到頂點Ei的最長路徑長度。在上圖中,Ee[4]=7。

  2 事件Ei的最遲允許開始時間:El(小寫L)[i]—在保證匯點En-1最遲允許開始時間El[n-1]等於整個工程所需時間的前提下,等於El[n-1]減去從Ei到En-1的最長路徑長度。

  3 活動ak的最早可能開始時間:e[k]—設該活動在有向邊<Ei,Ej>上,從源點E0到頂點Ei的最長路徑長度,即等於Ee[i]。

  4 活動ak的最遲允許開始時間:l(小寫L)[k]—設該活動在有向邊<Ei,Ej>上,在不會引起時間延誤的前提下,允許的最遲開始時間。l[k]=El[j]-dur(<Ei

,Ej>),其中dur(<Ei,Ej>)是完成該活動所需的時間,即有向邊<Ei,Ej>的權值。

  l[k]-e[k]表示活動ak最早可能開始時間和最遲允許開始時間的時間余量,也叫做松弛時間(slack time)。沒有時間余量的活動是關鍵活動。

  算法步驟:

  1 輸入頂點數和邊數,再輸入每條邊的起點編號、終點編號和權值。根據邊的信息,通過一維數組存儲每個頂點的入度和出度,建立鄰接表保存邊。每個頂點的Ee[i]設為0,El[i]設為100000000(表示無限大)。

  2 按拓撲排序遍歷所有頂點,更新Ee[i]。如果拓撲排序循環次數小於頂點數n,則說明網絡中存在有向環,不能繼續求關鍵路徑。更新Ee[i]的最大值(整個工程所需時間)。

  3 把所有匯點的最遲允許開始時間設為整個工程所需時間,按逆拓撲排序遍歷所有頂點,更新El[i]。

  4 通過DFS遍歷所有邊<Ei,Ej>。如果l[k]等於e[k],則說明該活動是關鍵活動。依次輸出關鍵活動上的頂點後構成關鍵路徑。

  在上圖中,關鍵路徑是a1-a4-a7-a10或a1-a4-a8-a11,完成整個工程所需時間是18。

  題目 PTA 數據結構與算法題目集(中文) 7-11 關鍵活動(30 分)

  多源點和多匯點例子:

 1 11 14
 2 1 2 4
 3 1 3 3
 4 2 4 5
 5 3 4 3
 6 4 5 1
 7 4 6 6
 8 5 7 5
 9 6 7 2
10 8 3 7
11 9 3 7
12 9 10 6
13 4 10 2
14 10 6 5
15 6 11 4

  技術分享

  結果如下:

1 21
2 3->4
3 4->10
4 6->11
5 8->3
6 9->3
7 10->6

  C++代碼如下:

技術分享
  1 //#include "stdafx.h"
  2 #include <iostream>
  3 #include <vector>
  4 #include <queue>
  5 
  6 using namespace std;
  7 
  8 struct node
  9 {
 10     int next, time;
 11 };
 12 
 13 int degree[2][110], t[2][110], maxtime;
 14 vector<node> v[2][110];
 15 
 16 int torder(int index, int n)
 17 {
 18     int i;
 19     queue<int> q;
 20 
 21     for(i = 1; i <= n; i++)
 22     {
 23         if(degree[index][i] == 0)
 24         {
 25             if(index == 1)
 26             {
 27                 t[1][i] = maxtime;
 28             }
 29 
 30             q.push(i);
 31         }
 32     }
 33 
 34     int cur, size, next, nexttime[2], curtime, count = 0;
 35     while(q.size() > 0)
 36     {
 37         cur = q.front();
 38         q.pop();
 39 
 40         count++;
 41 
 42         size = v[index][cur].size();
 43         for(i = 0; i < size; i++)
 44         {
 45             next = v[index][cur][i].next;
 46             degree[index][next]--;
 47 
 48             if(degree[index][next] == 0)
 49             {
 50                 q.push(next);
 51             }
 52 
 53             curtime = t[index][cur];
 54             nexttime[0] = curtime + v[index][cur][i].time;
 55             nexttime[1] = curtime - v[index][cur][i].time;
 56 
 57             if(index == 0 && nexttime[0] > t[0][next])
 58             {
 59                 t[0][next] = nexttime[0];
 60             }
 61             else if(index == 1 && nexttime[1] < t[1][next])
 62             {
 63                 t[1][next] = nexttime[1];
 64             }
 65         }
 66 
 67         if(index == 0 && t[0][cur] > maxtime)
 68         {
 69             maxtime = t[0][cur];
 70         }
 71     }
 72 
 73     if(count < n)
 74     {
 75         return 0;
 76     }
 77 
 78     return 1;
 79 }
 80 
 81 int main()
 82 {
 83     int n, m;
 84     scanf("%d%d", &n, &m);
 85 
 86     int i, a, b;
 87     node nod;
 88 
 89     for(i = 1; i <= m; i++)
 90     {
 91         scanf("%d%d%d", &a, &b, &nod.time);
 92 
 93         nod.next = b;
 94         v[0][a].push_back(nod);
 95 
 96         nod.next = a;
 97         v[1][b].push_back(nod);
 98 
 99         degree[1][a]++;
100         degree[0][b]++;
101     }
102 
103     for(i = 1; i <= n; i++)
104     {
105         t[0][i] = 0;
106         t[1][i] = 100000000;
107     }
108 
109     for(i = 0; i <= 1; i++)
110     {
111         if(torder(i, n) == 0)
112         {
113             printf("0\n");
114             return 0;
115         }
116     }
117 
118     printf("%d\n", maxtime);
119 
120     int size, j, next;
121     for(i = 1; i <= n; i++)
122     {
123         size = v[0][i].size();
124         for(j = size - 1; j >= 0; j--)
125         {
126             next = v[0][i][j].next;
127             if(t[1][next] - t[0][i] == v[0][i][j].time)
128             {
129                 printf("%d->%d\n", i, next);
130             }
131         }
132     }
133 
134     system("pause");
135     return 0;
136 }
View Code

  技術分享

  參考資料

  《圖論算法理論、實現及應用》

  06-圖8. 關鍵活動(30)

數據結構 計算關鍵路徑