编程语言
首页 > 编程语言> > Kruskal算法求最小生成树

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;
}

标签:const,int,Kruskal,d%,最小,算法,edge,复杂度
来源: https://www.cnblogs.com/ljfyyds/p/16490086.html