圖論:Prim演算法 求最小生成樹
阿新 • • 發佈:2022-05-10
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 }