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 行!
如有错误请在评论区积极指出。
觉得还行就点个赞吧,您的支持是本蒟蒻最大的动力。
原创文章,作者:wdmbts,如若转载,请注明出处:https://blog.ytso.com/276782.html