Kruskal算法
- 一、算法思想
- 二、问题思考
- 三、算法模板
![在这里插入图片描述](https://img-blog.csdnimg.cn/c849e8968511439f95c230200a28d4d4.png#pic_center)
本苟蒻发文,有任何不足欢迎大佬们斧正(>人<;)
一、算法思想
把边按照权值进行排序,用贪心的思想优先选取权值较小的边,并依次连接,若出现环则跳过此边(用并查集来判断是否存在环)继续搜,直到已经使用的边的数量比总点数少一即可。正确性证明基于如果某个连通图属于最小生成树,那么所有从外部连接到该连通图的边中的一条最短的边必然属于最小生成树。所以不难发现,当最小生成树被拆分成彼此独立的若干个连通分量的时候,所有能够连接任意两个连通分量的边中的一条最短边必然属于最小生成树。
二、问题思考
对于研究一个算法,我们要针对性的思考一些问题,才能把算法代码模板加以解剖和记忆。
三、算法模板
👉洛谷练习题:点我跳转
👉Acwing练习题:点我跳转
时间复杂度: O(mlogm)
算法结构:
①将所有边按权重从小到大排序
②枚举每条边a、b、权重c
if(a、b不连通)
将这条边也加入集合中
#include <bits/stdc++.h>
using namespace std;
const int N = 5010, M = 2e5+10;
int n, m;
int f[N];
struct Edge{
int a, b, w;
bool operator<(const Edge& W) const{
return w < W.w;
}
}edges[M];
int find(int x){
return x==f[x] ? x:f[x]=find(f[x]);
}
int main(){
scanf("%d %d", &n, &m);
for(int i = 1; i <= m; i++){
int a, b, w;
scanf("%d %d %d\n", &a, &b, &w);
edges[i] = {a, b, w};
}
sort(edges+1, edges + m + 1); // 1 是起点
int res = 0, cnt = 0; //res存储最小生成树所有边权和,cnt存当前边数
for(int i = 1; i <= n; i++) f[i] = i; //并查集初始化
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[a] = b;
res += w;
cnt++;
}
if(cnt == n-1) break; //如果到了n-1,后面再连边也没意义了
}
if(cnt < n-1) puts("impossible"); //最小生成树不存在
else printf("%d\n", res);
return 0;
}
路漫漫其修远兮,吾将上下而求索