【OI】Kruskal & ufs (克鲁斯卡与并查集)
Kruskal是有关于最小生成树的算法。
这个算法非常好理解,用一句话来概括就是:
从小到大找不同集合的边。
那么,具体是怎样的呢。
1.先把所有顶点初始化为一个连通分量。
2.从所有边中选择最小的(指权值)边,判断该边是否已经在当前构造的连通分量中,如果是,则放弃这条边,找下一条边。
3.重复第二步,直到所有点都被纳入到当前构造的连通分量中。
所以,这样的算法涉及到了查询当前边是否在集合中和合并一条边到集合中。
于是想到了并查集。
先贴并查集代码,并查集的思想是用一个父亲数组:fa[i]代表节点i的父亲,以此将某节点并为某节点儿子来合并,查询。

#include<iostream> using namespace std; int par[10001],ran[10001]; void init(int N) { for(int k=0;k<N;k++) { par[k]=k; } } int find(int x) { if(par[x]==x) { return x; } else { return find(par[x]); } } void unionn(int x,int y) { x=find(x); y=find(y); if(ran[x]<ran[y]) { par[x]=y; } else { par[y]=x; if(ran[x]==ran[y]) { ran[x]++; } } } bool same(int x,int y) { return find(x)==find(y); } int main() { int n,m,a,b,c; cin>>n>>m; init(n+1); for(int i=0;i<m;i++) { cin>>a>>b>>c; if(a==1) { unionn(b,c); } else { if(same(b,c)) { cout<<"Y"<<endl; } else { cout<<"N"<<endl; } } } return 0; }
然后,我们需要根据这份代码来进行克鲁斯卡算法。
根据之前的思路,可以写出这样的算法:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | void kruskal(){ sort(e+1,e+m+1,cmp);<br> int sum = 0; int num = 0; for ( int i = 1;i <= m;i++){ int s = e[i].s; int t = e[i].t; if (!same(s,t)){ printf ( "连接%d,%d\n" ,s,t); sum += e[i].v; union_(s,t); num++; } if (num >= n-1) break ; } printf ( "最小生成树权值和为%d,共有%d个节点" ,sum,num); } |
看起来似乎很好理解。
这也是一个贪心的思想。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· 开发者必知的日志记录最佳实践
· SQL Server 2025 AI相关能力初探
· Linux系列:如何用 C#调用 C方法造成内存泄露
· AI与.NET技术实操系列(二):开始使用ML.NET
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· 没有Manus邀请码?试试免邀请码的MGX或者开源的OpenManus吧
· 【自荐】一款简洁、开源的在线白板工具 Drawnix
· 园子的第一款AI主题卫衣上架——"HELLO! HOW CAN I ASSIST YOU TODAY
· Docker 太简单,K8s 太复杂?w7panel 让容器管理更轻松!