數據結構與算法 -- 圖的應用之最小生成樹問題

前言

  前面對 圖的存儲 和 **圖的遍歷(廣度優先/深度優先)**做了簡單的學習和了解,本篇文章,學習一下最小生成樹的問題,以及對應解決這個問題的兩種算法 普里姆算法克魯斯卡爾算法

1.最小生成樹問題

首先看下面一道面試題:

假設目前有N個頂點,每個頂點連接的路徑不一樣,設計一個算法,快速查找出能覆蓋所有頂點的路徑。

其實這個問題並不是求解兩點之間的最短路徑,而是設計一個路線,能覆蓋所有的頂點。

如下連通圖:

那麼覆蓋所有頂點的路徑有一下幾種

  • 方法一

    V0 ——> V5 ——> V4 --> V3 --> V2 -->V1 -->V8 --> V6 -->V7

    權重:11 + 26 + 20 + 22 + 18 + 21 + 24 + 19 = 161

  • 方案二

    V2 ——> V8 ——> V1 --> V0 --> V5 -->V6 -->V7 --> V3 -->V4
    權重:8 + 12 + 10 + 11 + 17 + 19 + 16 + 7 = 100

  • 方案三

    權重:8 + 12 + 10 + 11 + 16 + 19 + 16 + 7 = 99

由此可以看出,方法三是最優的方案,這就是最小生成樹。

最小生成樹:把構成連通網的最小代價的生成樹稱之爲最小生成樹。即假設有N個頂點,用N-1條邊,連接所有頂點,而且權重的和最小的路徑。

2.最小生成樹求解(普里姆(Prim)算法)

普里姆算法思路:

1. 定義兩個數組,adjvew 用來保存相關頂點下標,lowcost 保存頂點之間的權值。
2. 初始化兩個數組,將與 V0 相關的 V1-V8 的所有頂點的權值賦值給 lowcost
    adjvew[1-8],都賦值爲 0,表示都是與 V0 相關的頂點(後面循環修改)
3. 循環 lowcost 數組,根據權值,找到權值最新的頂點的下標 k
4. 更新 lowcost 數組
5. 循環所有頂點,找到與下標爲 k 的頂點,有關係的頂點,並更新 lowcost  數組和 adjvew 數組


注意:
更新 lowcost 數組的條件
1. 與下標爲 k 的頂點之間有連接
2. 當前下標爲 j 的頂點是否加入最小生成樹
3. 下標爲 k 的頂點與下標爲 j 的頂點的權值比較,小於,則更新,
    簡單說就是要比較之前存儲的權值,小於,則更新。

接下來,我們詳細的解析一下上面的思路:

  • 初始化 lowcostadjvew

lowcost 數組(將與 V0 相關的 V1-V8 的所有頂點的權值賦值給 lowcost

0 1 2 3 4 5 6 7 8
0 10 11

默認將V0加入到最小生成樹中,lowcost[0] = 01011 表示頂點V0 連接頂點V1V5的權值。

adjvew 數組(都賦值爲 0,表示都是與 V0 相關的頂點)

0 1 2 3 4 5 6 7 8
0 0 0 0 0 0 0 0 0

然後開始循環(從 i = 1 開始,默認第一個已經加入最小樹)

  • 第一次循環 i = 1

    由上面的表格看出,10 是最小的權值,

    此時,k = 1,在lowcost數組中10最小。且滿足更新 lowcost 數組的三個條件,

    所以,lowcost[1] = 0, 表示 V1 已經加入最小生成樹,並打印信息

    lowcost 數組

    0 1 2 3 4 5 6 7 8
    0 0 11

    然後,循環所有頂點,找到下標爲k頂點各邊權值小於此前這些頂點未被加入生成樹權值,然後更新lowcost 數組和adjvew 數組

      V2 未加入最小生成樹,且權值 18 < ∞,lowcost【2】= 18,adjvew【2】= 1
      V8 未加入最小生成樹,且權值 12 < ∞,lowcost【8】= 12,adjvew【8】= 1
      V6 未加入最小生成樹,且權值 16 < ∞,lowcost【6】= 16,adjvew【6】= 1
    

    lowcost 數組

    0 1 2 3 4 5 6 7 8
    0 0 18 11 16 12

    adjvew 數組(都賦值爲 0,表示都是與 V0 相關的頂點)

    0 1 2 3 4 5 6 7 8
    0 0 1 0 0 0 1 0 1

    18,16,12對應V2、V6、V8,是針對V1相關的頂點,

    1 是因爲 k = 1,表示與V1相連的頂點是V2、V6、V8

  • 第二次循環 i = 2

    lowcost 中找到 權值最小 11j = 5,便是 k = 5

    所以,lowcost[5] = 0,加入到最小生成樹中,並打印信息

    然後,循環所有頂點,找到下標爲k = 5頂點各邊權值小於此前這些頂點未被加入生成樹權值,然後更新lowcost 數組和adjvew 數組

      V6 未加入最小生成樹,且權值 17 > 16,不更新
      V4 未加入最小生成樹,且權值 26 < ∞,lowcost【4】= 26,adjvew【4】= 5
      V3 未加入最小生成樹,且權值 ∞  < ∞,不更新
    

    此時,lowcost 數組

    0 1 2 3 4 5 6 7 8
    0 0 18 26 0 16 12

    adjvew 數組(都賦值爲 0,表示都是與 V0 相關的頂點)

    0 1 2 3 4 5 6 7 8
    0 0 1 0 5 0 1 0 1

    1 ,表示與V1相連的頂點V2、V6、V8

    5 是因爲 k = 5,表示與V5相連的頂點是V4

  • 第三次循環 i = 3

    lowcost 中找到 權值最小12j = 8,便是 k = 8

    所以,lowcost[8] = 0,加入到最小生成樹中,並打印信息

    然後,循環所有頂點,找到下標爲k = 8頂點各邊權值小於此前這些頂點未被加入生成樹權值,然後更新lowcost 數組和adjvew 數組

      V2 未加入最小生成樹,且權值 8 < 18,lowcost【2】= 8,adjvew【2】= 8
      V3 未加入最小生成樹,且權值 21  < ∞,lowcost【3】= 21,adjvew【3】= 8
    

    此時,lowcost 數組

    0 1 2 3 4 5 6 7 8
    0 0 8 21 26 0 16 0

    V0、V1、V5、V8都已經加入最小生成樹

    adjvew 數組(都賦值爲 0,表示都是與 V0 相關的頂點)

    0 1 2 3 4 5 6 7 8
    0 0 8 8 5 0 1 0 1

    1 ,表示與V1相連的頂點V6、V8

    5 ,表示與V5相連的頂點是V4

    8 是因爲 k = 8,表示與V8相連的頂點是V2、V3

  • 第四次循環 i = 4

    lowcost 中找到 權值最小8j = 2,便是 k = 2

    所以,lowcost[2] = 0,加入到最小生成樹中,並打印信息

    然後,循環所有頂點,找到下標爲k = 2頂點各邊權值小於此前這些頂點未被加入生成樹權值,然後更新lowcost 數組和adjvew 數組

      V3 未加入最小生成樹,且權值 22  > 21,不更新
    

    此時,lowcost 數組

    0 1 2 3 4 5 6 7 8
    0 0 0 21 26 0 16 0

    V0、V1、V5、V8都已經加入最小生成樹

    adjvew 數組(都賦值爲 0,表示都是與 V0 相關的頂點)

    0 1 2 3 4 5 6 7 8
    0 0 8 8 5 0 1 0 1

    1 ,表示與V1相連的頂點V6、V8
    5 ,表示與V5相連的頂點是V4
    8 是因爲 k = 8,表示與V8相連的頂點是V2、V3

  • 第五次循環 i = 5

    lowcost 中找到 權值最小16j = 6,便是 k = 6

    所以,lowcost[6] = 0,加入到最小生成樹中,並打印信息

    然後,循環所有頂點,找到下標爲k = 6頂點各邊權值小於此前這些頂點未被加入生成樹權值,然後更新lowcost 數組和adjvew 數組

      V7 未加入最小生成樹,且權值 19  < ∞,lowcost【7】= 19,adjvew【7】= 6
      V3 未加入最小生成樹,且權值 22  > 21,不更新
    

    此時,lowcost 數組

    0 1 2 3 4 5 6 7 8
    0 0 0 21 26 0 0 19 0

    V0、V1、V2、V5、V6、V8都已經加入最小生成樹

    adjvew 數組(都賦值爲 0,表示都是與 V0 相關的頂點)

    0 1 2 3 4 5 6 7 8
    0 0 8 8 5 0 1 6 1

    1 ,表示與V1相連的頂點V6、V8

    5 ,表示與V5相連的頂點是V4

    8 ,表示與V8相連的頂點是V2、V3

    6 是因爲 k = 6,表示與V6相連的頂點是V7

  • 第六次循環 i = 6

    lowcost 中找到 權值最小19j = 7,便是 k = 7

    所以,lowcost[7] = 0,加入到最小生成樹中,並打印信息

    然後,循環所有頂點,找到下標爲k = 7頂點各邊權值小於此前這些頂點未被加入生成樹權值,然後更新lowcost 數組和adjvew 數組

      V4 未加入最小生成樹,且權值 7  < 26,lowcost【4】= 7,adjvew【4】= 7
      V3 未加入最小生成樹,且權值 16 < 21,lowcost【3】= 16,adjvew【3】= 7
    

    此時,lowcost 數組

    0 1 2 3 4 5 6 7 8
    0 0 0 16 7 0 0 0 0

    V0、V1、V2、V5、V6、V7、V8都已經加入最小生成樹

    adjvew 數組(都賦值爲 0,表示都是與 V0 相關的頂點)

    0 1 2 3 4 5 6 7 8
    0 0 8 7 7 0 1 6 1

    1 ,表示與V1相連的頂點V6、V8

    8 ,表示與V8相連的頂點是V2

    6 ,表示與V6相連的頂點是V7

    7 是因爲 k = 7,表示與V7相連的頂點是V3,V4

  • 第七次循環 i = 7
    lowcost 中找到 權值最小7j = 4,便是 k = 4

    所以,lowcost[4] = 0,加入到最小生成樹中,並打印信息

    然後,循環所有頂點,找到下標爲k = 4頂點各邊權值小於此前這些頂點未被加入生成樹權值,然後更新lowcost 數組和adjvew 數組

      V3 未加入最小生成樹,且權值 20 > 16,不更新
    

    此時,lowcost 數組

    0 1 2 3 4 5 6 7 8
    0 0 0 16 0 0 0 0 0

    V0、V1、V2、V4、V5、V6、V7、V8都已經加入最小生成樹

    adjvew 數組(都賦值爲 0,表示都是與 V0 相關的頂點)

    0 1 2 3 4 5 6 7 8
    0 0 8 7 7 0 1 6 1

    1 ,表示與V1相連的頂點V6、V8

    8 ,表示與V8相連的頂點是V2

    6 ,表示與V6相連的頂點是V7

    7 是因爲 k = 7,表示與V7相連的頂點是V3,V4

  • 第八次循環 i = 8

    lowcost 中找到 權值最小16j = 3,便是 k = 3

    所以,lowcost[3] = 0,加入到最小生成樹中,並打印信息

    然後,循環所有頂點,找到下標爲k = 3頂點各邊權值小於此前這些頂點未被加入生成樹權值,然後更新lowcost 數組和adjvew 數組

      V3 未加入最小生成樹,且權值 20 > 16,不更新
    

    此時,lowcost 數組

    0 1 2 3 4 5 6 7 8
    0 0 0 0 0 0 0 0 0

    V0、V1、V2、V3、V4、V5、V6、V7、V8都已經加入最小生成樹

    adjvew 數組(都賦值爲 0,表示都是與 V0 相關的頂點)

    0 1 2 3 4 5 6 7 8
    0 0 8 7 7 0 1 6 1

    1 ,表示與V1相連的頂點V6、V8

    8 ,表示與V8相連的頂點是V2

    6 ,表示與V6相連的頂點是V7

    7 是因爲 k = 7,表示與V7相連的頂點是V3,V4

代碼實現:

#define OK 1
#define ERROR 0
#define TRUE 1
#define FALSE 0

#define MAXEDGE 20
#define MAXVEX  20

typedef  int Status;

typedef struct {
    int arc[MAXVEX][MAXVEX];
    int numVertexes;
    int numEdges;
}MGraph;


/* Prim算法生成最小生成樹 */
void MiniSpanTree_Prim(MGraph G)
{
    
    int min, i, j, k = 0;
    int sum = 0;
    
    int adjvex[MAXVEX];  // 保存相關頂點下標
    int lowcost[MAXVEX]; // 保存相關頂點的權重
    
    // 初始化第一個權值爲0 ,將V0加入生成最小樹
    lowcost[0] = 0;
    // 初始化第一個頂點的下標爲0
    adjvex[0] = 0;
    
    // 初始化
    for (i = 1; i < G.numVertexes; i++) {
        // 將v0頂點與之有邊的權值存入數組
        lowcost[i] = G.arc[0][i];
        // 初始化默認都爲v0的下標
        adjvex[i]  = 0;
    }
    
    // 循環除了下標爲 0 以外的全部頂點,找到z權重最小且沒有加入到s最小樹中的頂點
    for (i = 1; i < G.numVertexes; i++) {
        min = INFINITY;
        j = 1; k = 0;
        while (j < G.numVertexes) {
            if (lowcost[j] != 0 && lowcost[j] < min) {
                // 讓當前權值成爲最小值,更新min
                min = lowcost[j];
                // 當前最小值的下標賦值給 k
                k = j;
            }
            j++;
        }
    }
    // 打印
    printf("(V%d, V%d) = %d\n", adjvex[k], k, G.arc[adjvex[k]][k]);
    sum += G.arc[adjvex[k]][k];
    
    // 當前頂點的權值設置爲0 ,標誌爲已經加入最小樹
    lowcost[k] = 0;
    
    // 循環所有頂點,找到與頂點k 相連接的頂點
    for (j = 1; j < G.numVertexes; j++) {
        if (lowcost[j] != 0 && G.arc[k][j] < lowcost[j]) {
            // 將較小的權值存入lowcost相應位置
            lowcost[j] = G.arc[k][j];
            // 下標爲k的頂點存入adjvex
            adjvex[j] = k;
        }
    }
    printf("sum = %d\n", sum);
}

2.最小生成樹求解(克魯斯卡爾算法)

克魯斯卡爾算法思路:

1.將 鄰接矩陣 轉換爲 邊表數組()
2.對邊表數組根據權重值按照從小到大的順序排序
3.遍歷所有的邊,打印不閉環的邊,通過 parent 數組找到邊的連接信息,避免閉環
4.如果不存在閉環問題,則加入到最小生成樹中,並修改 parent 數組

克魯斯卡爾算法詳細解析如下:

設計如下的邊表數據結構:

/* 對邊集數組Edge結構的定義 */
typedef struct
{
    int begin;   // 開始
    int end;     // 結束
    int weight;  // 權重
}Edge ;

那麼對上面所說的圖的邊表,排序後如下:

begin end weight
4 7 7
2 8 8
0 1 10
0 5 11
1 8 12
3 7 16
1 6 16
5 6 17
1 2 18
6 7 19
3 4 20
3 8 21
2 3 22
3 6 24
4 5 26

初始化parent數組,給初始值爲0,默頂點間認沒有連接

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

然後開始遍歷 排好序的邊表

定義nm ,分別表示beginend,如果 m = n,表示 beginend連接,就會產生閉合的環.

  • 0 次,i = 0

    begin = 4,end = 7, n = 4, m = 7
    n != m,所以parent[4] = 7,然後打印計算權重

parent數組如下:

0 1 2 3 4 5 6 7 8 9 10 11 12 13 14
0 0 0 0 7 0 0 0 0 0 0 0 0 0 0
  • 1 次,i = 1

    begin = 2,end = 8, n = 2, m = 8

    n != m,所以parent[2] = 8,然後打印計算權重

parent數組如下:

0 1 2 3 4 5 6 7 8 9 10 11 12 13 14
0 0 8 0 7 0 0 0 0 0 0 0 0 0 0
  • 2 次,i = 2

    begin = 0,end = 1, n = 0, m = 1
    n != m,所以parent[0] = 1,然後打印計算權重

parent數組如下:

0 1 2 3 4 5 6 7 8 9 10 11 12 13 14
1 0 8 0 7 0 0 0 0 0 0 0 0 0 0
  • 3 次,i = 3

    begin = 0,end = 5, n = 0, m = 5

    然後從parent 數組中,找到當前頂點的尾部下標( 幫助我們判斷2點之間是否存在閉環問題)
    parent[0] = 1,所以 n = 1parent[5] = 0,直接返回 5

    n != m,所以parent[1] = 5,然後打印計算權重

    parent數組如下:

0 1 2 3 4 5 6 7 8 9 10 11 12 13 14
1 5 8 0 7 0 0 0 0 0 0 0 0 0 0
  • 4 次,i = 4

    begin = 1,end = 8, n = 1, m = 8

    然後從parent 數組中,可以找到當前頂點的尾部下標( 幫助我們判斷2點之間是否存在閉環問題)
    parent[1] = 5,所以 n = 5parent[8] = 0,直接返回 8

    n != m,所以parent[5] = 8,然後打印計算權重

parent數組如下:

0 1 2 3 4 5 6 7 8 9 10 11 12 13 14
1 5 8 0 7 8 0 0 0 0 0 0 0 0 0
  • 5 次,i = 5

    begin = 3,end = 7, n = 3, m = 7

    然後從parent 數組中,找到當前頂點的尾部下標( 幫助我們判斷2點之間是否存在閉環問題)
    parent[3] = 0,所以 n = 3parent[7] = 0,直接返回 7

    n != m,所以parent[3] = 7,然後打印計算權重

    parent數組如下:

0 1 2 3 4 5 6 7 8 9 10 11 12 13 14
1 5 8 7 7 8 0 0 0 0 0 0 0 0 0
  • 6 次,i = 6

    begin = 1,end = 6, n = 1, m = 6

    然後從parent 數組中,找到當前頂點的尾部下標( 幫助我們判斷2點之間是否存在閉環問題)
    parent[1] = 5,parent[5] = 8,所以 n = 8parent[6] = 0,直接返回 6

    n != m,所以parent[8] = 6,然後打印計算權重

    parent數組如下:

0 1 2 3 4 5 6 7 8 9 10 11 12 13 14
1 5 8 7 7 8 0 0 6 0 0 0 0 0 0
  • 7 次,i = 7

    begin = 5,end = 6, n = 5, m = 6

    然後從parent 數組中,找到當前頂點的尾部下標( 幫助我們判斷2點之間是否存在閉環問題)
    parent[5] = 8,parent[8] = 6,所以 n = 6parent[6] = 0,直接返回 6

    n = m,所以不更新parent數組,所以不能加入最小樹

    parent數組如下:

0 1 2 3 4 5 6 7 8 9 10 11 12 13 14
1 5 8 7 7 8 0 0 6 0 0 0 0 0 0
  • 8 次,i = 8

    begin = 1,end = 2, n = 1, m = 2

    然後從parent 數組中,找到當前頂點的尾部下標( 幫助我們判斷2點之間是否存在閉環問題)
    parent[1] = 5,parent[5] = 8,parent[8] = 6,所以 n = 6parent[2] = 8,parent[8] = 6,直接返回 m = 6

    n = m,所以不更新parent數組,所以不能加入最小樹

    parent數組如下:

0 1 2 3 4 5 6 7 8 9 10 11 12 13 14
1 5 8 7 7 8 0 0 6 0 0 0 0 0 0
  • 9 次,i = 9

    begin = 6,end = 7, n = 6, m = 7

    然後從parent 數組中,找到當前頂點的尾部下標( 幫助我們判斷2點之間是否存在閉環問題)
    parent[6] = 0,所以 n = 6parent[7] = 9,直接返回 m = 6

    n != m,所以更新parent數組,所以parent[6] = 7,然後打印計算權重

    parent數組如下:

0 1 2 3 4 5 6 7 8 9 10 11 12 13 14
1 5 8 7 7 8 7 0 6 0 0 0 0 0 0
  • 10 次,i = 10

    begin = 3,end = 4, n = 3, m = 4

    然後從parent 數組中,找到當前頂點的尾部下標( 幫助我們判斷2點之間是否存在閉環問題)
    parent[3] = 7,parent[7] = 0,所以 n = 7parent[4] = 7,parent[7] = 0,直接返回 m = 7

    n = m,所以不更新parent數組,所以不能加入最小樹

    parent數組如下:

0 1 2 3 4 5 6 7 8 9 10 11 12 13 14
1 5 8 7 7 8 7 0 6 0 0 0 0 0 0
  • 11 次,i = 11

    begin = 3,end = 8, n = 3, m = 8

    然後從parent 數組中,找到當前頂點的尾部下標( 幫助我們判斷2點之間是否存在閉環問題)
    parent[3] = 7,parent[7] = 0,所以 n = 7parent[8] = 6,parent[6] = 7,直接返回 m = 7

    n = m,所以不更新parent數組,所以不能加入最小樹

    parent數組如下:

0 1 2 3 4 5 6 7 8 9 10 11 12 13 14
1 5 8 7 7 8 7 0 6 0 0 0 0 0 0
  • 12 次,i = 12

    begin = 2,end = 3, n = 2, m = 3

    然後從parent 數組中,找到當前頂點的尾部下標( 幫助我們判斷2點之間是否存在閉環問題)
    parent[2] = 8,parent[8] = 6,parent[6] = 7,所以 n = 7parent[3] = 7,parent[7] = 0,直接返回 m = 7

    n = m,所以不更新parent數組,所以不能加入最小樹

    parent數組如下:

0 1 2 3 4 5 6 7 8 9 10 11 12 13 14
1 5 8 7 7 8 7 0 6 0 0 0 0 0 0
  • 13 次,i = 13

    同上分析,m = n,不更新

  • 14 次,i = 14
    同上分析,m = n,不更新

    parent數組如下:

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

最終遍歷完所有的邊,找到最小樹

代碼實現:

#define OK 1
#define ERROR 0
#define TRUE 1
#define FALSE 0
#define MAXEDGE 20
#define MAXVEX 20
#define INFINITYC 65535

typedef int Status;
// 圖結構
typedef struct
{
    int arc[MAXVEX][MAXVEX];
    int numVertexes, numEdges;
}MGraph;
// 邊表結構
typedef struct {
    int begin;
    int end;
    int weight;
}Edge;

/* 交換權值以及頭和尾 */
void Swapn(Edge *edges,int i, int j)
{
    int tempValue;
    
    //交換edges[i].begin 和 edges[j].begin 的值
    tempValue = edges[i].begin;
    edges[i].begin = edges[j].begin;
    edges[j].begin = tempValue;
    
    //交換edges[i].end 和 edges[j].end 的值
    tempValue = edges[i].end;
    edges[i].end = edges[j].end;
    edges[j].end = tempValue;
    
    //交換edges[i].weight 和 edges[j].weight 的值
    tempValue = edges[i].weight;
    edges[i].weight = edges[j].weight;
    edges[j].weight = tempValue;
}

/* 對權值進行排序 */
void sort(Edge edges[],MGraph *G)
{
    //對權值進行排序(從小到大)
    int i, j;
    for ( i = 0; i < G->numEdges; i++)
    {
        for ( j = i + 1; j < G->numEdges; j++)
        {
            if (edges[i].weight > edges[j].weight)
            {
                Swapn(edges, i, j);
            }
        }
    }
    
    printf("邊集數組根據權值排序之後的爲:\n");
    for (i = 0; i < G->numEdges; i++)
    {
        printf("(%d, %d) %d\n", edges[i].begin, edges[i].end, edges[i].weight);
    }
    
}
int Find(int *parent, int f)
{
    while ( parent[f] > 0)
    {
        f = parent[f];
    }
    return f;
}
/* 生成最小生成樹 */
void MiniSpanTree_Kruskal(MGraph G)
{
    int i, j, n, m;
    int sum = 0;
    int k = 0;
    
    int parent[MAXVEX];
    Edge edges[MAXEDGE];
    
    // 構建邊表
    for (i = 0; i < G.numVertexes - 1; i++) {
        for (j = 1 + i; j < G.numVertexes; j++) {
            if (G.arc[i][j] < INFINITYC) {
                edges[k].begin = i;
                edges[k].end   = j;
                edges[k].weight   = G.arc[i][j];
                
                k++;
            }
        }
    }
    
    // 排序
    sort(edges, &G);
    
    // 初始化parent 數組爲0. 9個頂點;
    for (i = 0; i < MAXVEX; i++)
        parent[i] = 0;
    
    // 循環邊表
    for (i = 0; i < G.numEdges; i++) {
        //獲取begin,end 在parent 數組中的信息;
        //如果n = m ,將begin 和 end 連接,就會產生閉合的環.
        n = Find(parent,edges[i].begin);
        m = Find(parent,edges[i].end);
        
        // n與m不等,說明此邊沒有與現有的生成樹形成環路
        if (n != m) {
            parent[n] = m;
            printf("(%d, %d) %d\n", edges[i].begin, edges[i].end, edges[i].weight);
            sum += edges[i].weight;
        }
    }
    
    printf("sum = %d\n",sum);
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章