| 網路類型 | 頂點含義 | 邊/弧含義 | 權值含義 | 資料結構 |
|---|---|---|---|---|
| AOV 網 (Activity On Vertex) | 活動/任務 | 優先關係 | 無 | 鄰接表 |
| AOE 網 (Activity On Edge) | 事件/里程碑 | 活動/任務 | 持續時間 | 鄰接表 |
#define MAXVEX 100
typedef struct EdgeNode {
int adjvex;
int weight;
struct EdgeNode *next;
} EdgeNode;
typedef struct VertexNode {
int in; // 入度
int data;
EdgeNode *firstedge;
} VertexNode, AdjList[MAXVEX];
typedef struct {
AdjList adjList;
int numVertexes, numEdges;
} GraphAdjList, *GraphAdjListPtr;
int TopologicalSort(GraphAdjListPtr GL) {
EdgeNode *e;
int i, k, gettop;
int top = 0, count = 0;
int *stack = (int*)malloc(GL->numVertexes * sizeof(int));
// 入度為 0 入堆疊
for (i = 0; i < GL->numVertexes; i++)
if (GL->adjList[i].in == 0)
stack[++top] = i;
while (top != 0) {
gettop = stack[top--];
printf("%d -> ", GL->adjList[gettop].data);
count++;
for (e = GL->adjList[gettop].firstedge; e; e = e->next) {
k = e->adjvex;
if (--GL->adjList[k].in == 0)
stack[++top] = k;
}
}
free(stack);
return (count < GL->numVertexes) ? -1 : 0; // -1 表有環
}
時間:O(n + e) — 每頂點進出堆疊一次,每邊處理一次
空間:O(n) — 入度陣列、堆疊
ve(i):事件 i 最早發生時間 (從源點前向傳遞)vl(i):事件 i 最晚發生時間 (從匯點後向傳遞)e(k) = ve(m):活動最早開始時間l(k) = vl(n) - dut(<m,n>):活動最晚開始時間e(k) == l(k),無浮動時間ve[] (最早時間)vl[] = ve[終點]vl[] (最晚時間)e(k) == l(k) 的關鍵活動int *etv, *ltv; // 全域:最早/最晚時間
int *stack2; // 拓撲序列堆疊
int top2;
int TopologicalSort(GraphAdjListPtr GL) {
// ... 前面拓撲排序程式碼 ...
// 關鍵差異:計算 etv (最早時間)
top2 = 0;
etv = (int*)malloc(GL->numVertexes * sizeof(int));
for (i = 0; i < GL->numVertexes; i++) etv[i] = 0;
stack2 = (int*)malloc(GL->numVertexes * sizeof(int));
while (top != 0) {
gettop = stack[top--];
stack2[++top2] = gettop; // 記錄拓撲序列
count++;
for (e = GL->adjList[gettop].firstedge; e; e = e->next) {
k = e->adjvex;
if (--GL->adjList[k].in == 0)
stack[++top] = k;
// 更新最早時間:ve[k] = max(ve[k], ve[gettop] + weight)
if (etv[gettop] + e->weight > etv[k])
etv[k] = etv[gettop] + e->weight;
}
}
// ...
}
void CriticalPath(GraphAdjListPtr GL) {
EdgeNode *e;
int i, gettop, k, ete, lte;
TopologicalSort(GL); // 取得 etv[] 和 stack2[]
ltv = (int*)malloc(GL->numVertexes * sizeof(int));
for (i = 0; i < GL->numVertexes; i++)
ltv[i] = etv[GL->numVertexes - 1]; // 初始化為專案最早完成時間
// 逆拓撲序計算 ltv (最晚時間)
while (top2 != 0) {
gettop = stack2[top2--];
for (e = GL->adjList[gettop].firstedge; e; e = e->next) {
k = e->adjvex;
if (ltv[k] - e->weight < ltv[gettop])
ltv[gettop] = ltv[k] - e->weight;
}
}
// 找出關鍵活動
for (i = 0; i < GL->numVertexes; i++) {
for (e = GL->adjList[i].firstedge; e; e = e->next) {
k = e->adjvex;
ete = etv[i]; // 活動最早開始
lte = ltv[k] - e->weight; // 活動最晚開始
if (ete == lte)
printf("關鍵活動 <v%d,v%d> 長度:%d\n",
GL->adjList[i].data, GL->adjList[k].data, e->weight);
}
}
free(etv); free(ltv); free(stack2);
}
文章圖示專案:關鍵路徑為 V0→V1→V3→V5→V7,總工期 18 天。關鍵活動無延遲空間,非關鍵活動 (如 V1→V2) 有浮動時間可調度資源。
| 特性 | 拓撲排序 | 關鍵路徑 |
|---|---|---|
| 圖模型 | AOV 網 | AOE 網 |
| 核心輸出 | 可行執行順序 | 最短工期 + 關鍵任務 |
| 環路檢測 | 是 (輸出數 < n) | 是 (先做拓撲排序) |
| 時間複雜度 | O(n+e) | O(n+e) |
| 應用 | 依賴排序 | 專案管理、工期壓縮 |