ltv 若是某時間不完成,會影響後續其它活動的開始)數據結構
lte 若是某時間不開始,則自身的剩餘時間會不夠用,影響後面頂點狀態的完成時間點(從而推遲工期)ide
etv[n] 等於Vn的etv值 加上其後弧權值的和,可能存在多條路徑,取最大值指針
ete 等於 etv[n] 由於etv事件的結束,也是以其後弧活動的開始code
ltv[n] 等於Vn的ltv 減去 其前弧的權值,可能存在多條路徑,取最小值(也就是之後面最大權值的弧爲活動依據,不然會延期工程)blog
lte 等於 Vn的ltv 減去其前弧的權值(用此值和ete比較,若是相等則說明沒有空閒,在工程的關鍵路徑上), 只計算一次排序
圖來自《大話數據結構》事件
#include <stdio.h> #include <stdlib.h> /* * 實現《大話數據結構》p287圖7-9-11 關鍵路徑 */ #define MAXVEX 32 // 邊表節點類型 typedef struct EdgeNode { int adjVex; int weight; // 弧的權值 struct EdgeNode *next; }EdgeNode, *PE; // 頂點表節點類型 typedef struct VertexNode { int in; // 入度 int data; // 頂點的數據,簡單用數字標識 PE firstEdge; }VertexNode, *PV, AdjList[MAXVEX]; // 定義圖 typedef struct { AdjList adjList; int numVertex, numEdge; // 未使用numEdge }GraphAdjList, *PG; // 全局變量 int ete, lte, *etv, *ltv; int top2; // stack2的棧頂指針 int *stack2; // 複用拓撲排序的代碼,把打印頂點改成入棧操做 void create(PG); void topological(GraphAdjList); void display(GraphAdjList); void criticalPath(GraphAdjList); void criticalPath(GraphAdjList graph) { int i, gettop, k; PE e; // 初始化ltv ltv = (int *)malloc(sizeof(int)*graph.numVertex); for (i=0; i<graph.numVertex; i++) { ltv[i] = etv[graph.numVertex-1]; // ltv默認等於etv的最大值,即v9的etv } // 開始遍歷, 計算ltv while (top2 != 0) { // 出棧,先輸出的是V9頂點 gettop = stack2[top2--]; // 遍歷出棧頂點的邊表節點(V9的無邊表節點,因此不會的進行此循環) for (e = graph.adjList[gettop].firstEdge; e; e = e->next) { // 保存節點下標 k = e->adjVex; if (ltv[k] - e->weight < ltv[gettop]) // 取最小 ltv[gettop] = ltv[k] - e->weight; } } // 比較ete lte找到關鍵路徑 printf("關鍵路徑爲:\n"); for (i=0; i<graph.numVertex; i++) { ete = etv[i]; // 直接賦值 for (e = graph.adjList[i].firstEdge; e; e=e->next) { k = e->adjVex; lte = ltv[k] - e->weight; if (ete == lte) { printf("<%d, %d>len[%d] -> ", i, k, e->weight); // 簡單一些下村即頂點名 } } } putchar('\n'); } void display(GraphAdjList graph) { int i, k; PE e; for (i=0; i<graph.numVertex; ++i) { printf("v%d, in %d, arcs:", graph.adjList[i].data, graph.adjList[i].in); e = graph.adjList[i].firstEdge; while (e) { k = e->adjVex; printf("->%d", graph.adjList[k].data); e = e->next; } putchar('\n'); } } void topological(GraphAdjList graph) { int i; int *stack; // 存放入度非0的頂點下標 int top; // 棧頂指針下標 int gettop; // 取棧頂 int count; // 打印頂點(入度爲0)計算器 PE e; count = 0; top = 0; // 0爲表示棧爲空 stack = (int *)malloc(sizeof(int) * graph.numVertex); // 先掃一遍,初始化棧 for (i=0; i<graph.numVertex; i++) { if (graph.adjList[i].in == 0) stack[++top] = i; } // 添加etv stack2初始化 top2 = 0; stack2 = (int *)malloc(sizeof(int) * graph.numVertex); etv = (int *)malloc(sizeof(int) * graph.numVertex); for (i=0; i<graph.numVertex; i++) { etv[i] = 0; } // 若是存在入度爲0的頂點,則開始處理 printf("拓撲序列:\n"); while (top) { gettop = stack[top--]; // 出棧,同時更新棧頂指針 printf("%d ", graph.adjList[gettop].data); // 打印頂點 // 添加stack2入棧 stack2[++top2] = gettop; count++; // 刪除頂點相關的弧(操做爲弧頭頂點入度減1,若是減到0則弧頭頂點入棧) e = graph.adjList[gettop].firstEdge; while (e) { i = e->adjVex; if (! --graph.adjList[i].in) stack[++top] = i; // 添加計算etv邏輯 // 由於etv初始狀態都是0,因此會依次更新頂點的etv值 if (etv[gettop] + e->weight > etv[i]) etv[i] = etv[gettop] + e->weight; e = e->next; } } putchar('\n'); if (count == graph.numVertex) printf("拓撲排序成功, 無環\n"); else printf("拓撲排序失敗, 有環\n"); } void create(PG g) { int i; PE e; g->numVertex = 10; for (i=0; i<g->numVertex; i++) { g->adjList[i].data = i; // i即爲頂點名Vi g->adjList[i].firstEdge = NULL; } // 填充鄰接表(添加時順序保持與書中7-9-4一致《大話數據結構》) // v0 g->adjList[0].in = 0; e = (PE)malloc(sizeof(EdgeNode)); e->adjVex = 2; e->weight = 4; e->next = g->adjList[0].firstEdge; g->adjList[0].firstEdge = e; e = (PE)malloc(sizeof(EdgeNode)); e->adjVex = 1; e->weight = 3; e->next = g->adjList[0].firstEdge; g->adjList[0].firstEdge = e; // v1 g->adjList[1].in = 1; e = (PE)malloc(sizeof(EdgeNode)); e->adjVex = 4; e->weight = 6; e->next = g->adjList[1].firstEdge; g->adjList[1].firstEdge = e; e = (PE)malloc(sizeof(EdgeNode)); e->adjVex = 3; e->weight = 5; e->next = g->adjList[1].firstEdge; g->adjList[1].firstEdge = e; // v2 g->adjList[2].in = 1; e = (PE)malloc(sizeof(EdgeNode)); e->adjVex = 5; e->weight = 7; e->next = g->adjList[2].firstEdge; g->adjList[2].firstEdge = e; e = (PE)malloc(sizeof(EdgeNode)); e->adjVex = 3; e->weight = 8; e->next = g->adjList[2].firstEdge; g->adjList[2].firstEdge = e; // v3 g->adjList[3].in = 2; e = (PE)malloc(sizeof(EdgeNode)); e->adjVex = 4; e->weight = 3; e->next = g->adjList[3].firstEdge; g->adjList[3].firstEdge = e; // v4 g->adjList[4].in = 2; e = (PE)malloc(sizeof(EdgeNode)); e->adjVex = 7; e->weight = 4; e->next = g->adjList[4].firstEdge; g->adjList[4].firstEdge = e; e = (PE)malloc(sizeof(EdgeNode)); e->adjVex = 6; e->weight = 9; e->next = g->adjList[4].firstEdge; g->adjList[4].firstEdge = e; // v5 g->adjList[5].in = 1; e = (PE)malloc(sizeof(EdgeNode)); e->adjVex = 7; e->weight = 6; e->next = g->adjList[5].firstEdge; g->adjList[5].firstEdge = e; // v6 g->adjList[6].in = 1; e = (PE)malloc(sizeof(EdgeNode)); e->adjVex = 9; e->weight = 2; e->next = g->adjList[6].firstEdge; g->adjList[6].firstEdge = e; // v7 g->adjList[7].in = 2; e = (PE)malloc(sizeof(EdgeNode)); e->adjVex = 8; e->weight = 5; e->next = g->adjList[7].firstEdge; g->adjList[7].firstEdge = e; // v8 g->adjList[8].in = 1; e = (PE)malloc(sizeof(EdgeNode)); e->adjVex = 9; e->weight = 3; e->next = g->adjList[8].firstEdge; g->adjList[8].firstEdge = e; // v9 g->adjList[9].in = 2; } int main(void) { GraphAdjList graph; create(&graph); display(graph); topological(graph); criticalPath(graph); return 0; }
outputv8
[root@8be225462e66 c]# gcc criticalPath.c && ./a.out v0, in 0, arcs:->1->2 v1, in 1, arcs:->3->4 v2, in 1, arcs:->3->5 v3, in 2, arcs:->4 v4, in 2, arcs:->6->7 v5, in 1, arcs:->7 v6, in 1, arcs:->9 v7, in 2, arcs:->8 v8, in 1, arcs:->9 v9, in 2, arcs: 拓撲序列: 0 2 5 1 3 4 7 8 6 9 拓撲排序成功, 無環 關鍵路徑爲: <0, 2>len[4] -> <2, 3>len[8] -> <3, 4>len[3] -> <4, 7>len[4] -> <7, 8>len[5] -> <8, 9>len[3] -> [root@8be225462e66 c]#