1. 程式人生 > 其它 >圖論:Prim演算法 求最小生成樹

圖論:Prim演算法 求最小生成樹

Prim演算法 求最小生成樹     利用了藍白點思想,先將所有點標記為藍點。用一個數組布林陣列b 標記點的藍白,如果為true就是藍點,否則是白點。先定義一個整型變數mst=0,mst就是最小生成樹。然後用一個二維陣列w 記錄 邊i和邊j之間的權值,再用一個一維陣列mins 記錄的是藍點的最小邊權,這個mins陣列是關鍵。
  int w[51][51];//邊的權值
  int mins[51];//藍點的最小邊權
  bool b[51];//藍點標記
  int mst = 0;//最小生成樹的邊權和

  然後將所有點都初始化為藍點,並且將每個點的最小邊權先初始化為無窮大,因為是求最小生成樹。

for
(int i = 0; i <= n; ++i) { mins[i] = oo;//最小邊權初始化為最大 b[i] = true;//全部初始化為藍點 }//i等於0的點要初始化 方便後面每次比較找到一個最小的藍點

  然後先初始化所有點的邊權為無窮大,然後再輸入邊權,這樣兩個點之間有邊相連就有邊權,否則兩個點之間的邊權就是無窮大。

for (int i = 1; i <= n; ++i)
        for (int j = 1; j <= n; ++j)
            w[i][j] = oo;//先初始化邊的權值為無窮
    int
x, y, z; for (int i = 1; i <= m; ++i) { cin >> x >> y >> z; w[x][y] = w[y][x] = z;//儲存權值 }

  

  然後任選一個點開始,開始的點就把它的最小邊權設為0,初始化mins[開始點]=0,我們一般選1為起點。

 mins[1] = 0;//任選一點開始

  

  然後就要一個外層迴圈,迴圈n個點,每次迴圈都要選出一個邊權最小的藍點,所以要再加一個內層迴圈尋找mins值最小的點,把最小邊權加入mst,就相當於把這條邊加入了最小生成樹,因為第一次mins[1]=0,所以第一次相當於不加入邊,所以一共加入n-1條邊,剛好是最小生成樹的邊數,並且更新所有與選出的藍點鄰接的藍點的最小邊權mins值,因為更新,所以要再內層並列一個內層迴圈,遍歷所有鄰接的藍點,更新的轉移方程就是用藍點和鄰接點的藍點的邊權代替mins[鄰接點],但前提是邊權要更小才能更新。注意每次選出來藍點後要把藍點洗白,避免重複選。

  

for (int i = 1; i <= n; ++i)
    {
        //找到mins[k]值最小的藍點
        int k = 0;//初始化一個比較的點
        for (int j = 1; j <= n; ++j)
            if (b[j] && mins[j] < mins[k])
                k=j;//替換之
        b[k] = 0;//洗白找到的藍點
        mst += mins[k];//累加生成樹權值

        //修改與找到的藍點k相連的所有藍點
        for (int j = 1; j <= n; ++j)//列舉所有點
        {
            if (b[j] && w[k][j] < mins[j])
                mins[j] = w[k][j];
        }

    }

  

  完整程式碼:

 1 #include<iostream>
 2 using namespace std;
 3 int w[51][51];//邊的權值
 4 int mins[51];//藍點的最小邊權
 5 bool b[51];//藍點標記
 6 int mst = 0;//最小生成樹的邊權和
 7 int main()
 8 {
 9     int n, m;//n個點 m條邊
10     cin >> n >> m;
11     int oo = 0x7fffff;
12     for (int i = 1; i <= n; ++i)
13         for (int j = 1; j <= n; ++j)
14             w[i][j] = oo;//先初始化邊的權值為無窮
15     int x, y, z;
16     for (int i = 1; i <= m; ++i)
17     {
18         cin >> x >> y >> z;
19         w[x][y] = w[y][x] = z;//儲存權值
20     }
21     for (int i = 0; i <= n; ++i)
22     {
23         mins[i] = oo;//最小邊權初始化為最大
24         b[i] = true;//全部初始化為藍點
25     }//i等於0的點要初始化 方便後面每次比較找到一個最小的藍點
26     mins[1] = 0;//任選一點開始
27     for (int i = 1; i <= n; ++i)
28     {
29         //找到mins[k]值最小的藍點
30         int k = 0;//初始化一個比較的點
31         for (int j = 1; j <= n; ++j)
32             if (b[j] && mins[j] < mins[k])
33                 k=j;//替換之
34         b[k] = 0;//洗白找到的藍點
35         mst += mins[k];//累加生成樹權值
36 
37         //修改與找到的藍點k相連的所有藍點
38         for (int j = 1; j <= n; ++j)//列舉所有點
39         {
40             if (b[j] && w[k][j] < mins[j])
41                 mins[j] = w[k][j];
42         }
43 
44     }
45     cout << mst;
46     return 0;
47 }