Kruskal求最小生成树

Posted on 2022-03-26 17:10  ZheyuHarry  阅读(31)  评论(0编辑  收藏  举报

就如前面对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;
}

 

分析:这里有几个比较重要的点不要遗漏:

·要对并查集进行初始化,而且利用路径压缩并查集的方式来实现时间的最优化;

·我们是按照边权大小来进行的排序,所以我们一定要注意我们在定义结构体的时候一定要重载小于运算符;

整体来看,非常简单哈,小学奥数水平!