最小生成树 Prim & kruskal
最小生成树
给定一个图 G 用 n−1条边将点连起来,得到一颗边权之和最小的树。
最小生成树有两种算法,用哪种取决于 n,m 大小,边比较稀疏用 kruskal 完全图或者稠密图用Prim
Prim算法
将图中的点分为两个集合G1G2一个表示在生成树中的点,一个表示不在生成树的点。
开始所有点都在 G2 任选一个起点s加入G1 记录一个dis数组表示G2中的点到G1中的点的边权最小值,每次选dis值最小的点加入G1,直到得到生成树。
复杂度 O(n2)
inline void Prim(){ memset(dis,0x3f3f3f,sizeof(dis)); int tot = 0;//tot记录生成树边权之和 vis[s] = 1;//vis 记录是否在G1中 dis[1] = 0; int mini,k; for(int i=1;i<=n;++i)dis[i] = f[s][i]; // 边权,若没有则是正无穷 for(int i=1;i<n;++i){ mini = 0x3f3f3f; k = 0; for(int j=1;j<=n;++j){//找到dis最小的点 if(!vis[j] && dis[j] < mini){ mini = dis[j]; k = j; } } tot += dis[k]; vis[k] = 1; for(int j=1;j<=n;++j) if(f[k][j] < dis[j]) dis[j] = f[k][j];//更新边权最小值 } }
Kruskal算法
该算法复杂度为O(mlogm) m为边数
实现也比较简单好理解:
将边按照边权升序排列,每次取出权值最小的边,如果边的端点不在同一颗树就插入生成树,反之舍弃,直到插入n−1条边。
是否在同一颗树用并查集维护。
inline int find(int x){return f[x] == x ? x : f[x] = find(f[x]);} inline void kruskal(){ sort(g1+1,g1+1+m);//边权升序 for(int i=1;i<=n;++i)f[i] = i; for(int i=1;i<=m;++i){ int x = find(g1[i].x),y = find(g1[i].y); if(x == y)continue; f[x] = f[y]; add(g1[i].x,g1[i].y,g1[i].dis); add(g1[i].y,g1[i].x,g1[i].dis);//建树 } }
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· 没有Manus邀请码?试试免邀请码的MGX或者开源的OpenManus吧
· 园子的第一款AI主题卫衣上架——"HELLO! HOW CAN I ASSIST YOU TODAY
· 【自荐】一款简洁、开源的在线白板工具 Drawnix