Kruskal 算法的思路还是非常的简单的
- 先将所有的边都用一个结构体存起来
- 经所有的边按照权重排序即可(因为我们要求的其实就是极小连通子图,所以我们排序后可以直接对边进行连接即可,因为我们将所有的点都放入集合后,得到的边权之和一定是最小的)
- 最后就是函数内部实现,既然我们谈到了 集合中,那么如何判断这个点是否在集合内部呢? 这是我们就可以使用并查集这个算法了。
//并查集
int find(int x)
{
if(x != p[x]) return p[x] = find(p[x]);//路径压缩
}
接下来就是Kruskal算法
#include <iostream>
#include <algorithm>
#include <cstring>
using namespace std;
const int N = 2e5+10;
struct edge{
int a,b,w;
}ed[N];
int p[N];
bool cmp(edge e , edge f)
{
return e.w < f.w;
}
int n , m;
int find( int x )
{
if(p[x] != x ) return p[x] = find(p[x]);
}
int kruskal()
{
for( int i = 1 ; i <= n ; i++ ) p[i] = i;
int res = 0 , cnt = 0;
for( int i = 0 ; i < m ; i++ )
{
int a = ed[i].a , b = ed[i].b , w = ed[i].w;
int x = find(a) , y = find(b);
if(x != y )
{
cnt++;
p[x] = y;
res += w;
}
}
if( cnt < n - 1 ) return 0x4f4f4f4f;
else return res;
}
int main()
{
scanf("%d%d", &n, &m);
for( int i = 0 ; i < m ; i ++ )
{
int a,b,w;
scanf("%d%d%d",&a,&b,&w);
ed[i] = { a , b , w };
}
sort(ed,ed+m,cmp);
int ans = kruskal();
if( ans == 0x4f4f4f4f ) puts("impossible");
else printf("%d\n",ans);
return 0;
}