算法學習記錄-圖——應用之關鍵路徑(Critical Path)


 

之前我們介紹過,在一個工程中我們關心兩個問題:

(1)工程是否順利進行

(2)整個工程最短時間。

 

之前我們優先關心的是頂點(AOV),同樣我們也可以優先關心邊(同理有AOE)。(Activity On Edge Network)

看看百度百科上解釋:

AOE網:Activity on edge network

若在帶權的有向圖中,以頂點表示事件,以有向邊表示活動,邊上的權值表示活動的開銷(如該活動持續的時間),則此帶權的有向圖稱為AOE網。

如果用AOE網來表示一項工程,那么,僅僅考慮各個子工程之間的優先關系還不夠,更多的是關心整個工程完成的最短時間是多少;

哪些活動的延期將會影響整個工程的進度,而加速這些活動是否會提高整個工程的效率。

因此,通常在AOE網中列出完成預定工程計划所需要進行的活動,每個活動計划完成的時間,要發生哪些事件以及這些事件與活動之間的關系,

從而可以確定該項工程是否可行,估算工程完成的時間以及確定哪些活動是影響工程進度的關鍵。

很顯然,頂點表示事件,表示活動,邊的權則表示活動持續時間。

AOE一般用來估算工程的完成時間。

AOE表示工程的流程,把沒有入邊的稱為始點或者源點,沒有出邊的頂點稱為終點或者匯點。一般情況下,工程只有一個開始,一個結束,

所以正常情況下,AOE只有一個源點一個匯點。

 

AOV和AOE的區別:

1.AOV用頂點表示活動的網,描述活動之間的制約關系。

2.AOE用邊表示活動的網,邊上的權值表示活動持續的時間。

AOE 是建立在子過程之間的制約關系沒有矛盾的基礎之上,再來分析整個過程需要的時間。

 

AOE研究:

a.完成整個過程至少需要多長時間。

b.哪些活動影響工程的進度?


 

關鍵路徑:從源點到匯點具有最大長度的路徑。這個概念要清楚,一個工程不一定有一條關鍵路徑,可能會有多條。

關鍵活動:關鍵路徑上的活動(邊)。

針對上面AOE所關心的問題,要想縮短工程時間,就縮短關鍵路徑上的過程即可。(縮短后可能出現之前的關鍵路徑變成了非關鍵路徑)

 

由於AOE網上所有的活動是可以並行進行。這里舉一個例子,組裝一個變形金剛,需要頭,左膀右臂,身體,左腿右腿。

我們可以有兩種方法:1.先做好頭,做左手臂,做右手臂,做身體,做左腿,做右腿,然后再組裝。

          2.同時做頭、手臂、身體、腿的部分,每有一個頭、兩個手臂、兩個腿和一個身體的時候,就可以組裝了。

方法1.如我們計算機中的串行運行。這樣時間開銷是累加的。

方法2.如我們計算機中的並行運行。這樣時間開銷可以立體應用。在此方法中,同時做各個部位時間不同,比如做頭時間最長,那么整個一個

變形金剛所用的時間決定與做頭的時間,如果做手臂的時間是做頭時間的一半,那么就是說做手臂的時間點可以在頭做了一半的時候。只要不超過這個

時間點,手臂部分是不會影響整個工程的進度的。

 

這里定義四個定義:前兩個針對頂點,后兩個針對邊

事件最早開始時間:頂點Vi最早發生的時間。

事件最晚開始時間:頂點Vi最晚發生的時間,超出則會延誤整個工期。

活動的最早開始時間:邊Eg最早發生時間。

活動的最晚開始時間:邊Eg最晚發生時間。不推遲工期的最晚開工時間。

 

下面這個例子說明一下:

說明:上圖中J中為49,是最早開始時間。這里可以看到最早開始時間,就是完要成該頂點,前面的所有到該點的路徑都要已經完成。所以取路徑最大那一條。

補充說明:

事件最早開始時間:例子圖中,F點,ACF(9) 和 ADF(19),到達F點時候,保證AC和AD都完成,這樣 F才能開始,所以F點的最早開始時間取最大值,即19.

       可以看出,要求出到某一點的最早開始時間,則需要將匯於該點的所有路徑的時間求出來,取最大值。

事件最遲開始時間:這里是反着推,比如H點最遲開始時間,H到J 與 H到I到J兩條路徑,39 和 44,所謂最遲開始時間,就是超過這個時間就會影響整個工程進度,

         而這個時間是時間點,是從源點工程開始計時的,所以對於H點,39和44是相對於源點,如果取44,則H-J這條路徑就會拖延,最遲開始時間選擇最小值。

 

關鍵路徑的特點我們尋找關鍵路徑——關鍵路徑就是關鍵活動(頂點與頂點之間的邊組成),就是我們怎么判斷該頂點是否為關鍵活動(邊)的頂點,即判斷邊是否為關鍵活動。

        前面定義過,關鍵路徑就是圖中從源點到匯點最長(權值最大)的路徑。

        這條路徑就決定了整個工程的工期,這說明一個什么問題?

        關鍵路徑上的頂點與頂點之間的活動的應該最早開始和最遲開始時間是相等的,

        如果不等那么說明活動還有余額時間(在最早開始時間和最遲開始時間之間可以任選一個時間點開始),這說明還有其他活動是決定這個工程時間的,那就不是關鍵路徑了。


 

算法思想:

要准備兩個數組,a:最早開始時間數組etv,b:最遲開始時間數組。(針對頂點即事件而言)

1.從源點V0出發,令etv[0](源點)=0,按拓撲有序求其余各頂點的最早發生時間etv[i](1 ≤ i ≤ n-1)。同時按照上一章

拓撲排序的方法檢測是否有環存在。

2.從匯點Vn出發,令ltv[n-1] = etv[n-1],按拓撲排序求各個其余各頂點的最遲發生時間ltv[i](n-2 ≥ i ≥ 2);

3.根據各頂點的etv和ltv數組的值,求出弧(活動)的最早開工時間最遲開工時間,求每條弧的最早開工時間最遲開工時間是否相等,若相等,則是關鍵活動。

注意:1,2 完成點(事件)的最早和最遲。3根據事件來計算活動最早和最遲,從而求的該弧(活動)是否為關鍵活動。

 

 


 

關鍵代碼:

1.對圖進行拓撲排序,存儲了拓撲排序的順序,作為關鍵路徑的計算最遲開始時間的依據。

 

 1 int TopplogicalSort(GraphAdjList *g)
 2 {
 3     int count=0;
 4     eNode *e=NULL;
 5 
 6     StackType *stack=NULL;
 7     StackType top=0;
 8     stack = (StackType *)malloc((*g).numVextexs*sizeof(StackType));
 9     
10     int i;
11     
12     //初始化拓撲序列棧
13     g_topOfStk = 0;
14     //開辟拓撲序列棧對應的最早開始時間數組
15     g_etv = (int *)malloc((*g).numVextexs*sizeof(int));
16     //初始化數組
17     for (i=0;i<(*g).numVextexs;i++)
18     {
19         g_etv[i]=0;
20     }
21     //開辟拓撲序列的頂點數組棧
22     g_StkAfterTop = (int *)malloc(sizeof(int)*(*g).numVextexs);
23     
24     
25     
26 
27     for (i=0;i<(*g).numVextexs;i++)
28     {
29         if (!(*g).adjList[i].numIn)
30         {
31             stack[++top] = i;
32     //        printf("init no In is %c\n",g_init_vexs[i]);
33         }
34     }
35     
36 
37     while(top)
38     {
39         int geter = stack[top];
40         top--;
41 
42         //把拓撲序列保存到拓撲序列棧,為后面做准備
43         g_StkAfterTop[g_topOfStk++] = geter;
44         
45         printf("%c -> ",g_init_vexs[(*g).adjList[geter].idx]);
46         count++;
47 
48         //獲取當前點出度的點,對出度的點的入度減一(當前點要出圖)。
49         //獲取當前頂點的出度點表
50         e = (*g).adjList[geter].fitstedge;
51         while(e)
52         {
53             int eIdx = e->idx;
54             //選取的出度點的入度減一
55             int crntIN = --(*g).adjList[eIdx].numIn;
56             if (crntIN == 0)
57             {
58                 //如果為0,則說明該頂點沒有入度了,是下一輪的輸出點。
59                 stack[++top] = eIdx;
60         //        printf("running the vex is %c\n",g_init_vexs[e->idx]);
61             }
62 
63             //求出關鍵路徑
64             if ((g_etv[geter] + e->weigh) > g_etv[eIdx])
65             {
66                 g_etv[eIdx] = g_etv[geter] + e->weigh;
67             }
68 
69             e = e->next;
70         }
71     }
72     if (count < (*g).numVextexs)//如果圖本身就是一個大環,或者圖中含有環,這樣有環的頂點不會進棧而被打印出來。
73     {
74         return false;
75     }
76     else
77     {
78         printf("finish\n");
79         return true;
80     }
81     
82 }

 

 2.關鍵路徑代碼:

 1 void CriticalPath(GraphAdjList g)
 2 {
 3     int i;
 4     int geter;
 5     eNode *e = NULL;
 6     g_topOfStk--;
 7     //1.初始化最遲開始時間數組(匯點的最早開始時間(初值))
 8     g_ltv = (int *)malloc(sizeof(int)*g.numVextexs);
 9     for (i=0;i<g.numVextexs;i++)
10     {
11         g_ltv[i] = g_etv[g.numVextexs-1];
12     }
13 
14     //2.求每個點的最遲開始時間,從匯點到源點推。
15     while (g_topOfStk)
16     {
17         //獲取當前出棧(反序)的序號
18         geter = g_StkAfterTop[g_topOfStk--];
19         //對每個出度點
20         if (g.adjList[geter].fitstedge != NULL)
21         {
22             e = g.adjList[geter].fitstedge;
23             while(e != NULL)
24             {
25                 int eIdx = e->idx;
26                 if (g_ltv[eIdx] - e->weigh < g_ltv[geter])
27                 {
28                     g_ltv[geter] = g_ltv[eIdx] - e->weigh;
29                 }
30                 e = e->next;
31             }
32         }
33     }
34 
35     int ete,lte;//活動最早開始和最遲開始時間
36 
37     
38 
39     printf("start:->");
40     //3.求關鍵活動,即ltv和etv相等的
41     for (i=0;i<g.numVextexs;i++)
42     {
43         if (g.adjList[i].fitstedge)
44         {
45             e = g.adjList[i].fitstedge;
46             while(e)
47             {
48                 int eIdx = e->idx;
49                 //活動(i->eIdx)最早開始時間:事件(頂點) i最早開始時間
50                 ete = g_etv[i];
51                 //活動(i->eIdx)最遲開始時間:事件(頂點) eIdx 最遲開始時間 減去 活動持續時間
52                 lte = g_ltv[eIdx] - e->weigh; 
53                 if (ete == lte)
54                 {
55                     printf("(%c - %c)->",g_init_vexs[i],g_init_vexs[eIdx]);
56                 }
57                 e= e->next;
58             }
59         }
60     }
61     printf(" end\n");
62 }

 

編程所用的圖:

拓撲排序結果:

 

過程:

1.從J開始,無后繼,不做任何事情;

2.G,G的ltv為27,ltv-weight = 27-2 < 27,所以G的ltv為25;

3.I,I的ltv為27,ltv-weight = 27 -3 < 27,所以I的ltv為24;

4.H,H的ltv為24(I的ltv),24-5 < 24,所以H 的ltv為19;

依次類推。。。

 

完成top排序和關鍵路徑后:

全局存放各個頂點的最早開始和最遲開始時間:

完整代碼:

  1 // grp-top.cpp : 定義控制台應用程序的入口點。
  2 //
  3 // grp-top.cpp : 定義控制台應用程序的入口點。
  4 //
  5 
  6 #include "stdafx.h"
  7 #include <stdlib.h>
  8 
  9 
 10 #define MAXVEX 100
 11 #define IFY 65535
 12 
 13 
 14 typedef char VertexType;
 15 typedef int  EdgeType;
 16 typedef int  IdxType;
 17 typedef int QueueType;
 18 typedef int StackType;
 19 
 20 
 21 //-------
 22 int *g_etv = NULL;
 23 int *g_ltv = NULL;
 24 int *g_StkAfterTop;
 25 int g_topOfStk;
 26 
 27 
 28 ///---------------------------------------
 29 //邊節點
 30 typedef struct EdgeNode{
 31     IdxType idx;
 32     int weigh;
 33     struct EdgeNode* next;
 34 }eNode;
 35 
 36 //頂點節點
 37 typedef struct VexNode{
 38     int numIn;        //入度數量
 39     IdxType idx;
 40     eNode *fitstedge;
 41 }vNode;
 42 
 43 //圖的集合:包含了一個頂點數組
 44 typedef struct {
 45     vNode adjList[MAXVEX];
 46     int numVextexs,numEdges;
 47 }GraphAdjList;
 48 
 49 ///-----------------------------------
 50 /*VertexType g_init_vexs[MAXVEX] = {'A','B','C','D','E','F','G','H','I','J','K','L'};
 51 
 52 char *g_input[] = {
 53     "A->B->C->D",
 54     "B->E",
 55     "C->F->I->J",
 56     "D->E->I->J",
 57     "E",
 58     "F->K",
 59     "G->F->H->K",
 60     "H->I",
 61     "I->J->L",
 62     "J->E->K",
 63     "K->L",
 64     "L"
 65 };*/
 66 
 67 ///-----------------------------------
 68 VertexType g_init_vexs[MAXVEX] = {'A','B','C','D','E','F','G','H','I','J'};
 69 
 70 char *g_input[] = {
 71     "A->B->C",
 72     "B->D->E",
 73     "C->D->F",
 74     "D->E",
 75     "E->G->H",
 76     "F->H",
 77     "G->J",
 78     "H->I",
 79     "I->J",
 80     "J",
 81     NULL
 82 };
 83 
 84 char *g_input_weigh[] = {
 85     "3,4",//A
 86     "5,6",//B
 87     "8,7",//C
 88     "3",//D
 89     "9,4",//E
 90     "6",//F
 91     "2",//G
 92     "5",//H
 93     "3",//I
 94     " ",//J
 95     NULL
 96 };
 97 //===============================================================
 98 //隊列
 99 
100 //隊列節點
101 typedef struct Node {
102     QueueType data;
103     struct Node *next;
104 }QNode,*qQNode;
105 
106 //隊列指示
107 typedef struct {
108     int length;
109     qQNode frnt,rear;    
110 }spQueue;
111 
112 void init_Queue(spQueue *Q)
113 {
114     (*Q).frnt = NULL;
115     (*Q).rear = NULL;
116     (*Q).length = 0;
117 }
118 bool isEmptyQueue(spQueue Q)
119 {
120     if (Q.length == 0)
121     {
122         return true;
123     }
124     return false;
125 }
126 //進隊
127 void unshiftQueue(spQueue *Q,QueueType elem)
128 {
129     //隊列空
130     if (isEmptyQueue(*Q))
131     {
132         qQNode n = (qQNode)malloc(sizeof(QNode));
133         n->data = elem;
134         n->next = NULL;
135 
136         (*Q).frnt = n;
137         (*Q).rear = n;
138         (*Q).length = 1;
139     }
140     else
141     {
142         qQNode n = (qQNode)malloc(sizeof(QNode));
143         n->data = elem;
144         n->next = NULL;
145 
146         (*Q).rear->next = n;
147 
148         (*Q).rear = n;
149         (*Q).length++;
150     }
151 }
152 
153 //出隊
154 QueueType shiftQueue(spQueue *Q)
155 {
156     if (isEmptyQueue(*Q))
157     {
158         printf("Warning:Queue is empty!!!\n");
159         return NULL;
160     }
161     if ((*Q).length == 1)
162     {
163         QueueType sh = (*Q).frnt->data;
164         (*Q).frnt = NULL;
165         (*Q).rear = NULL;
166         (*Q).length = 0;
167         return sh;
168     }
169     QueueType sh = (*Q).frnt->data;
170     (*Q).frnt = (*Q).frnt->next;
171     (*Q).length--;
172 
173     return sh;
174 }
175 
176 //打印隊列
177 void prt_que(spQueue que)
178 {
179     if (isEmptyQueue(que))
180     {
181         return ;
182     }
183     qQNode pos = que.frnt;
184     while(que.rear->next != pos && pos != NULL)
185     {
186         printf(" %d ",pos->data);
187         pos = pos->next;
188     }
189     printf("\n");
190 }
191 //===============================================================
192 
193 ///-------
194 //由節點找節點的序號
195 IdxType strFindIdx(char ch)
196 {
197     int i=0;
198     VertexType *p = g_init_vexs;
199     while(p != NULL)
200     {
201         if(*p == ch)
202         {
203             return i;
204         }
205         p++;
206         i++;
207     }
208     return i;
209 }
210 
211 //由序號找節點
212 VertexType idxFindStr(IdxType i)
213 {
214     return g_init_vexs[i];
215 }
216 
217 void prt_strings(char *p)
218 {
219     char *pos = p;
220     while (NULL != *pos)
221     {
222         printf("%c",*pos);
223         pos++;
224     }
225     printf("\n");
226 }
227 
228 void prt_strArrays(char *p[],int num)
229 {
230     char **pos = p; 
231     int i=0;
232     while( *pos != NULL && i < num)
233     {
234         prt_strings(*pos);
235         pos++;
236         i++;
237     }
238 }
239 
240 //自己規定:頂點只能是大寫。
241 bool isVexter(char p)
242 {
243     if (p>='A' && p<='Z')
244     {
245         return true;
246     }
247     return false;
248 }
249 
250 bool isNumeric(char p)
251 {
252     if (p >= '0' && p <= '9')
253     {
254         return true;
255     }
256     return false;
257 }
258 
259 void init_GrapAdjList(GraphAdjList *g,char **str,char **wstr)
260 {
261     char **pos = str;
262     
263     int cnt=0;
264     int vcnt = 0;
265     char **wpos = wstr;//weight value
266 
267     //入度清零
268     int i;
269     for (i=0;i<MAXVEX;i++)
270     {
271         (*g).adjList[i].numIn = 0;
272     }
273 
274     while (*pos != NULL) //g_input的每行的首指針
275     {
276         int i=0;
277         while(**pos != NULL) //g_input的每行字母
278         {
279             if(isVexter(**pos)) //判斷是否為頂點(我規定‘A’-‘Z’之間為頂點標志)
280             {
281                 if (i == 0) //建立頂點的節點
282                 {
283                     (*g).adjList[cnt].idx = strFindIdx(**pos);
284                     (*g).adjList[cnt].fitstedge = NULL;
285                     
286                     i=1;
287                 }
288                 else if(i == 1) //建立第一個邊的節點
289                 {
290                     eNode* n = (eNode*)malloc(sizeof(eNode));
291                     n->idx = strFindIdx(**pos);
292                     n->next = NULL;
293 
294                     //weight
295                     while (!isNumeric(**wpos))
296                     {
297                         (*wpos)++;
298                     }
299                     n->weigh = **wpos-'0';
300                     (*wpos)++;
301 
302                     (*g).adjList[cnt].fitstedge = n;
303                     i=2;
304 
305                     //添加入度
306                     int iidx = strFindIdx(**pos);
307                     (*g).adjList[iidx].numIn++;
308                 }
309                 else //邊節點連接到前一個邊節點上
310                 {    
311                     eNode* n = (eNode*)malloc(sizeof(eNode));
312                     n->idx = strFindIdx(**pos);
313                     n->next = NULL;
314 
315                     //weight
316                     while (!isNumeric(**wpos))
317                     {
318                         (*wpos)++;
319                     }
320                     n->weigh = **wpos-'0';
321                     (*wpos)++;
322 
323                     //first splist
324                     eNode *r = (*g).adjList[cnt].fitstedge;
325                     while (r->next != NULL)
326                     {
327                         r = r->next;
328                     }
329                     r->next = n;
330 
331                     //添加入度
332                     int iidx = strFindIdx(**pos);
333                     (*g).adjList[iidx].numIn++;
334                 }
335             }
336             (*pos)++; 
337         }
338 
339         wpos++;
340         cnt++;
341         pos++;
342         
343     }
344     (*g).numVextexs = cnt;
345 }
346 
347 int TopplogicalSort(GraphAdjList *g)
348 {
349     int count=0;
350     eNode *e=NULL;
351 
352     StackType *stack=NULL;
353     StackType top=0;
354     stack = (StackType *)malloc((*g).numVextexs*sizeof(StackType));
355     
356     int i;
357     
358     //初始化拓撲序列棧
359     g_topOfStk = 0;
360     //開辟拓撲序列棧對應的最早開始時間數組
361     g_etv = (int *)malloc((*g).numVextexs*sizeof(int));
362     //初始化數組
363     for (i=0;i<(*g).numVextexs;i++)
364     {
365         g_etv[i]=0;
366     }
367     //開辟拓撲序列的頂點數組棧
368     g_StkAfterTop = (int *)malloc(sizeof(int)*(*g).numVextexs);
369     
370     
371     
372 
373     for (i=0;i<(*g).numVextexs;i++)
374     {
375         if (!(*g).adjList[i].numIn)
376         {
377             stack[++top] = i;
378     //        printf("init no In is %c\n",g_init_vexs[i]);
379         }
380     }
381     
382 
383     while(top)
384     {
385         int geter = stack[top];
386         top--;
387 
388         //把拓撲序列保存到拓撲序列棧,為后面做准備
389         g_StkAfterTop[g_topOfStk++] = geter;
390         
391         printf("%c -> ",g_init_vexs[(*g).adjList[geter].idx]);
392         count++;
393 
394         //獲取當前點出度的點,對出度的點的入度減一(當前點要出圖)。
395         //獲取當前頂點的出度點表
396         e = (*g).adjList[geter].fitstedge;
397         while(e)
398         {
399             int eIdx = e->idx;
400             //選取的出度點的入度減一
401             int crntIN = --(*g).adjList[eIdx].numIn;
402             if (crntIN == 0)
403             {
404                 //如果為0,則說明該頂點沒有入度了,是下一輪的輸出點。
405                 stack[++top] = eIdx;
406         //        printf("running the vex is %c\n",g_init_vexs[e->idx]);
407             }
408 
409             //求出關鍵路徑
410             if ((g_etv[geter] + e->weigh) > g_etv[eIdx])
411             {
412                 g_etv[eIdx] = g_etv[geter] + e->weigh;
413             }
414 
415             e = e->next;
416         }
417     }
418     if (count < (*g).numVextexs)//如果圖本身就是一個大環,或者圖中含有環,這樣有環的頂點不會進棧而被打印出來。
419     {
420         return false;
421     }
422     else
423     {
424         printf("finish\n");
425         return true;
426     }
427     
428 }
429 void CriticalPath(GraphAdjList g)
430 {
431     int i;
432     int geter;
433     eNode *e = NULL;
434     g_topOfStk--;
435     //1.初始化最遲開始時間數組(匯點的最早開始時間(初值))
436     g_ltv = (int *)malloc(sizeof(int)*g.numVextexs);
437     for (i=0;i<g.numVextexs;i++)
438     {
439         g_ltv[i] = g_etv[g.numVextexs-1];
440     }
441 
442     //2.求每個點的最遲開始時間,從匯點到源點推。
443     while (g_topOfStk)
444     {
445         //獲取當前出棧(反序)的序號
446         geter = g_StkAfterTop[g_topOfStk--];
447         //對每個出度點
448         if (g.adjList[geter].fitstedge != NULL)
449         {
450             e = g.adjList[geter].fitstedge;
451             while(e != NULL)
452             {
453                 int eIdx = e->idx;
454                 if (g_ltv[eIdx] - e->weigh < g_ltv[geter])
455                 {
456                     g_ltv[geter] = g_ltv[eIdx] - e->weigh;
457                 }
458                 e = e->next;
459             }
460         }
461     }
462 
463     int ete,lte;//活動最早開始和最遲開始時間
464 
465     
466 
467     printf("start:->");
468     //3.求關鍵活動,即ltv和etv相等的
469     for (i=0;i<g.numVextexs;i++)
470     {
471         if (g.adjList[i].fitstedge)
472         {
473             e = g.adjList[i].fitstedge;
474             while(e)
475             {
476                 int eIdx = e->idx;
477                 //活動(i->eIdx)最早開始時間:事件(頂點) i最早開始時間
478                 ete = g_etv[i];
479                 //活動(i->eIdx)最遲開始時間:事件(頂點) eIdx 最遲開始時間 減去 活動持續時間
480                 lte = g_ltv[eIdx] - e->weigh; 
481                 if (ete == lte)
482                 {
483                     printf("(%c - %c)->",g_init_vexs[i],g_init_vexs[eIdx]);
484                 }
485                 e= e->next;
486             }
487         }
488     }
489     printf(" end\n");
490 }
491 
492 
493 int _tmain(int argc, _TCHAR* argv[])
494 {
495     GraphAdjList grp;
496     printf("print Matix: of Vextexs:\n");
497     prt_strArrays(g_input,10);
498     printf("print Matix: of Weigh:\n");
499     prt_strArrays(g_input_weigh,10);
500 
501     init_GrapAdjList(&grp,g_input,g_input_weigh);
502     printf("Top sort:\n");
503     if (!TopplogicalSort(&grp))
504     {
505         printf("grp wrong!\n");
506     }
507     
508     CriticalPath(grp);
509 
510     getchar();
511     return 0;
512 }


測試結果:

 

 

 

 


免責聲明!

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



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