Kruskal算法求最小生成树


AcWing 859

最小生成树的定义:

给定一张边带权的无向图 /(G=(V,E)/),其中 /(V/) 表示图中点的集合,/(E/)表示图中边的集合,/(n=|V|/),/(m=|E|/)

由$ V$ 中的全部 /(n/) 个顶点和 /(E/) 中 /(n−1/) 条边构成的无向连通子图被称为 /(G/) 的一棵生成树,其中边的权值之和最小的生成树被称为无向图 /(G/) 的最小生成树。

然后我们看Kruskal的算法思想

1.将所有边按照权重从小到大排序,时间复杂度为/(O(m/log m)/)

2.枚举每条边/(a,b/)的权重/(c/),如果/(a,b/)不连通的话,我们就把这一条边添加到集合当中。并查集实现合并、查询,时间复杂度/(O(m)/)

时间复杂度是很快的,所以在稀疏图当中,用/(Kruskal/)就可以了。

#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;

const int N = 200010;
int n,m;

int p[N];//并查集的数组
struct Edge{
    int a,b,w;
    bool operator < (const Edge &W) const//重载运算符,用于后面排序
    {
        return w < W.w;
    }
}edge[N];


int find(int x)  // 并查集
{
    if (p[x] != x) p[x] = find(p[x]);
    return p[x];
}


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);
        edge[i] = {a,b,w};
    }
    sort(edge, edge + m);
    for (int i = 1; i <= n; i ++ ) p[i] = i;
    
    int res = 0;// 最小生成树里的所有权重之和
    int cnt = 0;//当前加了多少条边
    for (int i = 0; i < m; i ++ )
    {
        int a = edge[i].a, b = edge[i].b, w = edge[i].w;
        a = find(a), b = find(b);//并查集查找根节点
        
        if(a != b)
        {
            p[a] = b;//合并
            res += w;
            cnt ++ ;
        }
    }
    
    if(cnt < n - 1) puts("impossible");
    else printf("%d",res);
    return 0;
}

原创文章,作者:carmelaweatherly,如若转载,请注明出处:https://blog.ytso.com/275193.html

(0)
上一篇 2022年7月18日
下一篇 2022年7月18日

相关推荐

发表回复

登录后才能评论