kruskal (克魯斯卡爾) 算法與前面的 prim(普里姆)算法都是求最小生成樹的算法,prim 在沒有任何優化的情況下時間複雜度爲O(n^2) kruskal 的時間複雜度與使用的排序算法有關 若用快排(qsort) 時間複雜度爲 O(N log N) ;兩者還有一個區別:prim
算法 以點爲單位採用迭代的思想逐步生成最小樹,kruskal 算法以邊爲單位 藉助並查集的思想和操作 生成最小樹
簡單介紹一下kruskal算法:首先將所有的邊進行一遍排序 (遞增順序)然後從最小的一條邊開始 ,若將此邊加入到最小生成樹的集合中不會產生迴路就將其添加進去直到 存入了 n-1 條邊結束。
特別需要注意的是最後要判斷一下並查集有幾個連通集若大於一則說明沒有最小生成樹
實現代碼:
//kruskal 算法
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#define MAXN 100
typedef struct{ //定義一個儲存邊的結構體
int a;
int b;
int value;
}edge;
int pre[MAXN]; //並查集
int find(int a) //這是並查集查找祖先的函數
{
if (pre[a] == a)
return a;
else return pre[a] = find(pre[a]); //路徑壓縮
}
void join(int a,int b){ //這是並查集合並祖先的函數
int fa = find(a);
int fb = find(b);
if (fa == fb)
return ;
pre[fa] = fb;
}
void init() //初始化並查集
{
int i;
for (i=0;i<MAXN;i++)
pre[i] = i;
return ;
}
int cmp (void const *a,void const *b){ //qsort() 所要用到的比較函數,是一個升序的比較函數
int va = ((pedge)a)->value;
int vb = ((pedge)b)->value;
return va - vb;
}
void kruskal (int n,int m){ //kruscal 函數
int i, start, end, value, sum = 0,flag = 0; // i 是循環變量,start 和 end 是一條邊的兩個端點,value 是邊的權值,sum 記錄最小生成樹的權值的和 ,flag 用來判斷是否生成了最下生成樹;
edge edges[MAXN]; //用來存邊的結構體數組
init(); //調用初始化函數
for (i=0;i<m;i++) //將邊逐個輸入近數組
{
scanf("%d%d%d",&start,&end,&value);
edges[i].a = start;
edges[i].b = end;
edges[i].value = value;
}
qsort(edges,m,sizeof(edges[0]),cmp); //調用 qsort 函數 將邊按權值排成升序序列
for (i=0;i<m;i++)
{
if (find(edges[i].a) != find(edges[i].b)) //若邊的兩個端點在不同的集合中就能將邊添入
{
sum += edges[i].value; //將添入的邊的權值相加
join (edges[i].a,edges[i].b);
}
}
for (i=1;i<=n;i++) //若並查集中只有一個集合那就說明生成了 最小生成樹
{
if (find(i) == i)
flag++;
}
if (flag > 1)
printf("-1\n");
else
printf("%d\n",sum);
}
int main (){
int n, m;
scanf("%d%d",&n,&m);
kruskal(n,m);
}