ICode9

精准搜索请尝试: 精确搜索
首页 > 编程语言> 文章详细

Kruskal 算法

2022-07-24 23:03:21  阅读:154  来源: 互联网

标签:Kruskal 最小 生成 算法 edges 集合


Kruskal 算法

1.Kruskal 算法介绍

最小生成树:

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

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

Kruskal 算法:

Kruskal 算法是图论最小生成树问题算法的一种,利用并查集的方式实现,多用于稀疏图,时间复杂度为 \(O(mlogm)\),\(m\) 为边数。

2.Kruskal 算法例题

给定一个 \(n\) 个点 \(m\) 条边的无向图,图中可能存在重边和自环,边权可能为负数。

求最小生成树的树边权重之和,如果最小生成树不存在则输出 impossible

输入格式

第一行包含两个整数 \(n\) 和 \(m\)。

接下来 \(m\) 行,每行包含三个整数 \(u,v,w\),表示点 \(u\) 和点 \(v\) 之间存在一条权值为 \(w\) 的边。

输出格式

共一行,若存在最小生成树,则输出一个整数,表示最小生成树的树边权重之和,如果最小生成树不存在则输出 impossible

数据范围

\(1≤n≤105\),
\(1≤m≤2*105\),
图中涉及边的边权的绝对值均不超过 \(1000\)。

输入样例:

4 5
1 2 1
1 3 2
1 4 3
2 3 2
3 4 4

输出样例:

6

注:此题目来源于AcWing第859题

3.Kruskal 算法思路

Kruskal$算法将一个连通块当做一个集合。

Kruskal首先将所有的边按从小到大顺序排序(一般使用快排),并认为每一个点都是孤立的,分属于 \(n\) 个独立的集合。然后按顺序枚举每一条边。

如果这条边连接着两个不同的集合,那么就把这条边加入最小生成树,这两个不同的集合就合并成了一个集合;

如果这条边连接的两个点属于同一集合,就跳过。直到选取了 \(n-1\)条边为止。

4.Kruskal 算法原理

Kruskal 算法每次都选择一条最小的,且能合并两个不同集合的边,一张 \(n\) 个点的图总共选取 \(n-1\) 次边。

因为每次我们选的都是最小的边,所以最后的生成树一定是最小生成树。每次我们选的边都能够合并两个集合,最后 \(n\) 个点一定会合并成 一个集合。

通过这样的贪心策略,Kruskal算法就能得到一棵有 \(n-1\) 条边,连接着 \(n\) 个点的最小生成树。

注:来源于网络

5.Kruskal 算法代码(注释已全部标出)

#include<iostream>
#include<algorithm>
using namespace std;
const int N=100005,M=200005;
int n,m;
int f[N];
struct Edge{
    int a,b,w;
    bool operator< (const Edge &W)const{
        return w<W.w;
    }//重载一下小于号,如果不会可以去看cmp函数
}edges[M];
/*
bool cmp(Edge a,Edge b){
    return a.w<b.w;
}
*/
int find(int x){
    if(f[x]!=x) f[x]=find(f[x]);//如果x非父节点,就继续找
    return x;//是则返回x
} 
int kruskal(){
    int res=0,cnt=0;//res记录最小生成树的树边权重之和,cnt记录的是全部加入到树的集合中边的数量(可能有多个集合)
    for(int i=1;i<=m;i++){
        int a=edges[i].a,b=edges[i].b,w=edges[i].w;
        a=find(a),b=find(b);
        if(a!=b){
            f[b]=a;//将a,b所在的两个集合连接起来
            res+=w;//因为加入的是a-b的这一条边,将a,b所在的两个集合连接之后,全部集合中的边数加1
            cnt++;//加入到集合中的边的权重之和
        }	
    }
    if(cnt<n-1) return 0x3f3f3f3f;
    return res;
}
int main(){
    cin>>n>>m;
    for(int i=1;i<=m;i++)
        cin>>edges[i].a>>edges[i].b>>edges[i].w;
    sort(edges+1,edges+m+1);//将边的权重按照大小一一排序
    //sort(edges+1,edges+m+1,cmp)
    for(int i=1;i<=n;i++) f[i]=i;//初始化并查集
    int t=kruskal();
    if(t==0x3f3f3f3f) cout<<"impossible";
    else cout<<t;
    return 0;
}

完awa~

109 行!

如有错误请在评论区积极指出。

觉得还行就点个赞吧,您的支持是本蒟蒻最大的动力。

标签:Kruskal,最小,生成,算法,edges,集合
来源: https://www.cnblogs.com/XiaoHei666/p/16515762.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有