演算法:求解AOE網的關鍵路徑

來源:互聯網
上載者:User

前面我們簡要地介紹了AOE網和關鍵路徑的一些概念,本文接著對求解關鍵路徑程式的主要函數進行分析。現有一AOE網圖7-9-4所示,我們使用鄰接表格儲存體結構,注意與拓撲排序時鄰接表結構不同的地方在於,這裡弧表結點增加了weight域,用來儲存弧的權值。


求解事件的最早發生時間etv的過程,就是我們從頭至尾找拓撲序列的過程,因此在求關鍵路徑之前,需要先調用一次拓撲序列演算法的代碼來計算etv 和 拓撲序列列表,我們針對前面講過的AOV網與拓撲排序的程式進行改進,代碼如下(參考《大話資料結構》):

 C++ Code 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
/* 拓撲排序,若GL無迴路,則輸出拓撲排序序列並返回1,若有迴路返回0。 */
bool TopologicalSort(GraphAdjList GL)
{
    EdgeNode *pe;
    int i, k, gettop;
    int top = 0;/* 用於棧指標下標  */
    int count = 0;/* 用於統計輸出頂點的個數  */
    /* 建棧將入度為0的頂點入棧  */
    int *stack = (int *)malloc(GL->numVertexes * sizeof(int));

    for (i = 0; i < GL->numVertexes; i++)
        if (0 == GL->adjList[i].in)
            stack[++top] = i;/* 將入度為0的頂點入棧 */

    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));

    cout << "TopologicalSort ..." << endl;

    while (top != 0)
    {
        gettop = stack[top--];
        cout << GL->adjList[gettop].data << " -> ";
        count++;  /* 輸出i號頂點,並計數 */

        stack2[++top2] = gettop; /* 將彈出的頂點序號壓入拓撲序列的棧 */

        for (pe = GL->adjList[gettop].firstedge; pe; pe = pe->next)
        {
            k = pe->adjvex;
            /* 將i號頂點的鄰接點的入度減1,如果減1後為0,則入棧 */
            if (!(--GL->adjList[k].in))
                stack[++top] = k;
            /* 求各頂時間點事件的最早發生時間etv值 */
            if ((etv[gettop] + pe->weight) > etv[k])
                etv[k] = etv[gettop] + pe->weight;
        }
    }
    cout << endl;
    if (count < GL->numVertexes)
        return false;
    else
        return true;
}


在程式開始處我們聲明了幾個全域變數:

int *etv,*ltv; /* 事件最早發生時間和最遲發生時間數組,全域變數 */
int *stack2;   /* 用於儲存拓撲序列的棧 */
int top2;   /* 用於stack2的指標 */

其中stack2用來儲存拓撲序列,以便後面求關鍵路徑時使用。

上面的拓撲排序函數中除了增加了第12~19行,29行,38~39行,其他跟前面講過的AOV網與拓撲排序沒什麼區別。

第12~19行初始化全域變數etv數組、top2和stack2的過程。第29行就是將本來要輸出的拓撲序列壓入全域棧stack2中。第38~39行很關鍵,是求etv數組的每一個元素的值,具體求值辦法參見AOE網和關鍵路徑。


下面來看求關鍵路徑的演算法代碼。

 C++ Code 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
/* 求關鍵路徑,GL為有向網,輸出G的各項關鍵活動 */
void CriticalPath(GraphAdjList GL)
{
    EdgeNode *pe;
    int i, j, k, gettop;
    int 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];/* 初始化 */

    cout << "etv :  ";
    for (i = 0; i < GL->numVertexes; i++)
        cout << etv[i] << ' ';
    cout << endl;

    while (top2 != 0)/* 出棧是求ltv */
    {
        gettop = stack2[top2--];
        /* 求各頂時間點事件的最遲發生時間ltv值 */
        for (pe = GL->adjList[gettop].firstedge; pe; pe = pe->next)
        {
            k = pe->adjvex;
            if (ltv[k] - pe->weight < ltv[gettop])
                ltv[gettop] = ltv[k] - pe->weight;
        }
    }

    cout << "ltv :  ";
    for (i = 0; i < GL->numVertexes; i++)
        cout << ltv[i] << ' ';
    cout << endl;
    /* 求ete,lte和關鍵活動 */
    for (j = 0; j < GL->numVertexes; j++)
    {
        for (pe = GL->adjList[j].firstedge; pe; pe = pe->next)
        {
            k = pe->adjvex;
            ete = etv[j];/* 活動最早發生時間 */
            lte = ltv[k] - pe->weight;/* 活動最遲發生時間 */
            if (ete == lte) /* 兩者相等即在關鍵路徑上 */
                cout << "<v" << GL->adjList[j].data << " - v"
                     << GL->adjList[k].data << "> length: " << pe->weight << endl;
        }
    }
}

函數第7行調用求拓撲序列的函數,執行完畢後,全域數組etv和棧stack2 7-9-6所示,top2 = 10,也就是說,對於每個事件的最早發生時間,我們已經計算出來了。


第11~12行初始化全域變數ltv數組,因為etv[9] = 27,所以數組ltv值現在為全27。

第19~29行是計算ltv 數組的迴圈,具體方法參見AOE網和關鍵路徑。

當程式執行到第36行,etv和ltv數組的值7-9-9


比如etv[1] = 3, 而ltv[1] = 7,表示如果單位是天的話,哪怕v1整個事件在第7天才開始,也可以保證整個工程的按期完成,可以提前v1事件開始時間,但最早也得第3天開始。

第36~47行是求另兩個變數,活動最早開始時間ete和活動最晚開始時間lte,並對相同下標的它們進行比較。兩重迴圈嵌套是對鄰接表的頂點和每個頂點的弧表遍曆,具體方法參見AOE網和關鍵路徑,舉例來說,7-9-10,當j = 0時,當k = 2, ete = lte,
表示

弧<v0, v2> 是關鍵路徑,因此列印;當k = 1, ete != lte, 故弧<v0, v1> 不是關鍵路徑。



j = 1 一直到 j = 9為止,做法是完全相同的,最後輸出的結果如,最終關鍵路徑7-9-11所示。




聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.