最小生成樹問題---Prim算法與Kruskal算法實現(MATLAB語言實現)


  2015-12-17晚,復習,甚是無聊,閱《復雜網絡算法與應用》一書,得知最小生成樹問題(Minimum spanning tree)問題。記之。

  何為:連通且不含圈的圖稱為樹。

  圖T=(V,E),|V|=n,|E|=m,下列關於樹的說法等價:

  1. T是一個樹。
  2. T無圈,且m=n-1。
  3. T連通,且m=n-1。
  4. T無圈,但每加一新邊記得到唯一一個圈。
  5. T連通,但任舍去一邊就不連通。
  6. T中任意兩點,有唯一道路相連。

 

  何為生成樹:若圖G=(V,E)的生成子圖是一棵樹,則稱該樹為圖G的生成樹,也稱支撐樹,簡稱為圖G的數。圖G中屬於生成樹的邊稱為數枝(Branch)。

  何為最小生成樹:連通圖G=(V,E),每條邊上有非負權L(e)。一棵樹上所有樹枝權的總和,稱為這個生成樹的權。具有最小權的生成樹稱為最小生成樹,也就是說最小支撐樹,簡稱最小樹。

  私以為,兩種算法其實都是貪心,所以需要嚴格的證明。由於最近時間零散、數學久置未學、對算法領域沒有系統了解。所以不進行深入探討(也就是說證明),僅以一個簡單實例做一個入門級的了解。

  Prim算法:

  給定連通賦權圖G=(V,E,W),其中W為鄰接矩陣,設兩個集合P和Q,其中P用於存放G的最小生成樹中的節點,集合Q存放G的最小G的最小生成樹中的邊。另集合P的初值為P={v1}(假設構造最小生成樹時從v1出發),集合Q的初值為P={空集}。

  (1)P = {v1},Q = {空集};

  (2)while P ~= Q

    找到最小邊pv,其中p∈P,v∈V-P;

    P = P + {v};

    Q = Q + {pv};

    end

   Kruskal算法

  (1)選e1∈E(G),使得w(e1) = min(選e1的權值最小)。

  (2)e1,e2,...,ei已選好,則從E(G)-{e1,e2,...,ei}中選取ei+1,使得G[{e1,e2,...,ei,ei+1}]中無圈,且,w(ei+1) = min。

  (3)直到選得en-1為止。

  以下是問題:

一個鄉有9個自然村,其間道路及各道路長度如圖所示,各邊上數字代表距離。問如何架設電線最短。

  

預輸入:

1 A = zeros(9);
2 A(1,2:9) = [2 1 3 4 4 2 5 4];
3 A(2,[3, 9]) = [4 1];
4 A(3, 4) = 1;
5 A(4, 5) = 1;
6 A(5, 6) = 5;
7 A(6, 7) = 2;
8 A(7, 8) = 3;
9 A(8, 9) = 5;

 

Prim算法實現:

 1 A = A+A';
 2 A(A==0) = Inf;
 3 P = zeros(1, 9);
 4 P(1,1) = 1;
 5 V = 1:9;
 6 V_P = V - P;
 7 link = zeros(8,2);
 8 k=1;
 9 while k<9
10     p = P(P~=0);
11     v = V_P(V_P~=0);
12     pv = min(min(A(p,v)));
13     [x, y] = find(A==pv);
14     for i=1:length(x)
15         if  any(P==x(i)) && any(V_P==y(i))集合判斷,關鍵!
16             P(1,y(i)) = y(i);
17             V_P = V - P;
18             link(k, :) = [x(i), y(i)];
19             k = k+1;
20             break;
21         end
22     end
23 end

輸出:

>> link
link =
     1     3
     3     4
     4     5
     1     2
     2     9
     1     7
     7     6
     7     8

 

Kruskal算法實現:

 1 A = sparse(A');
 2 A(A==0) = Inf; 3 B = sparse(9, 9);
 4 link = graphallshortestpaths(B, 'directed', false);
 5 while sum(sum(link)) == Inf%如果不連通,則和無窮大
 6     ind = find(A==min(min(A)));
 7     [x, y] = ind2sub(size(A), ind);%尋找最短邊
 8     for i=1:length(x)
 9         if link(x(i), y(i))==Inf%判斷是否連通,關鍵!!
10             B(x(i), y(i)) = A(x(i), y(i));
11             A(x(i), y(i))=Inf;%取差集
12         end
13     end
14     link = graphallshortestpaths(B, 'directed', false);
15 end

輸出:

B =
   (2,1)        2
   (3,1)        1
   (7,1)        2
   (9,2)        1
   (4,3)        1
   (5,4)        1
   (7,6)        2
   (8,7)        3

 

所以結果是:

  

(算法實現寫於2015-12-18)

  下一步工作,用其他語言實現,復雜度分析,深入論證算法正確性

  另外,代碼中使用了graphallshortestpaths函數,這是最短路徑的問題。關於最短路徑將在下一篇講述。其實MATLAB有關於求求最小生成樹的函數graphminspantree,關於這一套函數,將結合官網資料,以后做梳理。

 1  A = sparse(A');
 2 >> graphminspantree(A)
 3 ans =
 4    (2,1)        2
 5    (3,1)        1
 6    (7,1)        2
 7    (9,2)        1
 8    (4,3)        1
 9    (5,4)        1
10    (7,6)        2
11    (8,7)        3

  如此,可直接求得最小生成樹。


免責聲明!

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



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