1.概念
簡單說,最小生成樹是一副連通加權無向圖中一棵權值最小的生成樹。最小生成樹其實是最小權重生成樹的簡稱。
一個連通圖可能有多個生成樹。當圖中的邊具有權值時,總會有一個生成樹的邊的權值之和小於或者等於其它生成樹的邊的權值之和。廣義上而言,對於非連通無向圖來說,它的每一連通分量同樣有最小生成樹,它們的並被稱爲最小生成森林。
有關生成樹和最小生成樹的具體概念可以參考[維基百科]。
2.Prime方法求解代碼示例
// Minimum spanning tree
// prime algorithm
#define N 6
#define MAXINT 0x7FFFFFFF
// 將頂點使用變好數字表示,如果是其他字符或者字符串表示可以通過Hash映射成數字,關於這部分在《數據結構與算法分析C語言描述》書中有講到。
int v[N] = {0,1,2,3,4,5};
// 這裏給出的是從命令行或者文件中讀取到的鄰接矩陣,基於兩個假設:
// 1. 頂點到其自身設爲0
// 2. 當前頂點到其他頂點如果沒有連接則表示爲0,不爲0的地方表示兩個頂點組成的邊的權重
int adj_w[N][N] = {
{0, 6, 1, 5, 0, 0},
{6, 0, 5, 0, 3, 0},
{1, 5, 0, 5, 6, 4},
{5, 0, 5, 0, 0, 2},
{0, 3, 6, 0, 0, 6},
{0, 0, 4, 2, 6, 0}};
int prime(int v[], int adj_w[][N])
{
// 用來記錄相應位置的頂點是否已經遍歷過了
int vis[N] = {0};
// 用來記錄從頭開始的最小生成樹生成過程,可以打印查看如何產生的
int path[N] = {0};
// 記錄最小生成樹的權重和
int sum = 0;
// 與當前頂點相關的邊的權重記錄
int dis[N] = {0};
// 與當前頂點相連的邊中的最小權重值
int min_weight = 0;
// 在當前頂點處理過程中選擇的下一個頂點,也就是生成的方向
int node = 0;
// 爲了能夠在後續的邊權重中進行比較和記錄,先把不相鄰的頂點對應的鄰接矩陣權重值設爲無窮大
for (int i=0; i<n; i++) {
for (int j=0; j<n; j++) {
if (i!=j && adj_w[i][j]==0) {
adj_w[i][j] = MAXINT;
}
}
}
// 以第0個點爲起點,先將與之相連的所有邊的權重記錄下來
path[0] = 0;
vis[0] = 1;
for (int i=0; i<n; i++)
{
dis[i] = adj_w[0][i];
}
for (int i=1; i<n; i++)
{
min_weight = MAXINT;
for (int j=i; j<n; j++) {
if (vis[j]==0 && dis[j]>0 && dis[j]<min_weight) {
min_weight = dis[j];
node = j;
}
}
if (min_weight==MAXINT) break;
vis[node] = 1;
path[i] = node;
sum += min_weight;
// 找到下一個節點後要更新與它相關的邊的權重值
for (int j=0; j<n; j++) {
if (vis[j]==0 && adj_w[node][j]<dis[j])
dis[j] = adj_w[node][j];
}
}
printf("Traversal path: ");
for (int i=0; i<n; i++) {
printf("%d -> ");
if (n-1==i)
printf("\n");
}
return sum;
}
參考資料
[1] ACM第四站————最小生成樹(普里姆算法) https://blog.nowcoder.net/n/d11f4dcf65dc4794ba09c134a42d35ab?from=nowcoder_improve
[2] 【ACM】最小生成樹(Prim算法) https://blog.csdn.net/TwT520Ly/article/details/53543759