1. 程式人生 > 其它 >Kruskal求最小生成樹

Kruskal求最小生成樹

就如前面對Dijkstra演算法進行堆優化一般,我們在這裡也要對前面的Prim演算法進行優化,啊,不對,徹底換個新思路;

既然我們本身是要求最小生成樹對吧,所以我們肯定要讓邊權越小越好,那麼如果我把邊權按照從小到大進行排序,然後遍歷,如果說這條邊的兩個點的根節點已經相同,也就是在同一個集合中了,那麼就不要這條邊權;

 

所以這裡實現的思路是利用並查集的想法,我們來看兩個點它本身有沒有已經相連,且通過邊權更小的方式相連,如果相連了,別的就都不需要了,因為這裡是從小到大遍歷,根本不存在什麼需不需要更新前面的邊權的這種問題;

 

直接上程式碼:

//是使用並查集進行優化判斷是否已經形成迴路
#include<bits/stdc++.h>


#define maxn 200010

using namespace std;
int n, m,INF = 0x3f3f3f3f;
int p[maxn];
struct EDGE
{
int a,b,w;
bool operator < (const EDGE & W){
return w<W.w;
}
}edge[maxn];
int find(int x){
if(p[x] != x) p[x] = find(p[x]);
return p[x];
}

int kruskal()
{
sort(edge+1,edge+m+1); //先排序


for(int i = 1;i<=n;i++) p[i] = i; //初始化並查集
int res = 0 , cnt = 0;
for(int i = 1;i<=m;i++)
{
int a = find(edge[i].a);
int b = find(edge[i].b);
if(a!=b)
{
p[a] = b;
cnt++;
res += edge[i].w;
}
}
if(cnt < n-1) return INF;

else return res;
}

int main()
{
cin >> n >> m;
for(int i = 1; i<=m;i++){
cin >> edge[i].a >> edge[i].b >> edge[i].w ;
}
int t = kruskal();
if(t == INF) cout << "impossible" << '\n';
else cout << t << '\n';
return 0;
}

 

分析:這裡有幾個比較重要的點不要遺漏:

·要對並查集進行初始化,而且利用路徑壓縮並查集的方式來實現時間的最優化;

·我們是按照邊權大小來進行的排序,所以我們一定要注意我們在定義結構體的時候一定要過載小於運算子;

整體來看,非常簡單哈,小學奧數水平!