当前位置: 首页 > news >正文

Kruskal与Prim:最小生成树双雄对决

一、上期回顾

掌握 Floyd 多源最短路算法,三层循环实现任意两点间最短路径,适配小规模图。 今天学习最小生成树 (MST),在连通图中选出边权和最小的连通子图,覆盖所有顶点且无环。

二、最小生成树基础概念

  1. 定义:给定连通无向带权图,选取 n-1 条边,连接全部 n 个顶点,且所有边权之和最小,该子树即为最小生成树。
  2. 核心性质
    • 包含图中所有顶点
    • 恰好顶点数-1条边,无回路
    • 总边权和全局最小
  3. 适用场景:城市修路、网络布线、管道铺设、集群组网等求最小成本问题。
  4. 主流两种实现:Kruskal 克鲁斯卡尔Prim 普里姆

三、算法一:Kruskal 克鲁斯卡尔算法

1. 核心思想(贪心 + 并查集)

  1. 将所有边按权值从小到大排序
  2. 依次遍历每条边,用并查集判断两个顶点是否连通
  3. 不连通则选中这条边,合并两个集合;连通则跳过(避免成环)
  4. 选够n-1条边即可结束

2. 完整代码模板

#include <iostream> #include <vector> #include <algorithm> using namespace std; const int N = 1005; // 边结构体:起点u、终点v、权值w struct Edge { int u, v, w; bool operator<(const Edge& e) const { return w < e.w; // 按权值升序排序 } }; vector<Edge> edges; int parent[N]; // 并查集父节点数组 int n, m; // n顶点数,m边数 // 并查集初始化 void init() { for(int i = 1; i <= n; ++i) parent[i] = i; } // 查找+路径压缩 int find(int x) { if(parent[x] != x) parent[x] = find(parent[x]); return parent[x]; } // Kruskal 算法,返回最小生成树总权值 int kruskal() { init(); sort(edges.begin(), edges.end()); // 边排序 int sum = 0; // 总权值 int cnt = 0; // 已选边数 for(auto& e : edges) { int fu = find(e.u); int fv = find(e.v); if(fu != fv) { parent[fv] = fu; sum += e.w; cnt++; if(cnt == n - 1) // 选够n-1条边,提前退出 break; } } // 未选够边数,说明图不连通,无生成树 if(cnt < n - 1) return -1; return sum; } int main() { cin >> n >> m; edges.resize(m); for(int i = 0; i < m; ++i) { cin >> edges[i].u >> edges[i].v >> edges[i].w; } int res = kruskal(); if(res == -1) cout << "图不连通,无法生成最小生成树" << endl; else cout << "最小生成树总权值:" << res << endl; return 0; }

3. 特点与复杂度

  • 复杂度:\(O(m\log m)\),主要耗时在边排序
  • 优势:适合边稀疏的图(边数远小于顶点数),代码简洁
  • 依赖:必须配合并查集判断连通性、防环

四、算法二:Prim 普里姆算法

1. 核心思想(贪心 + 邻接矩阵 / 邻接表)

  1. 维护两个集合:已加入生成树的顶点集合、未加入集合
  2. 每次选取连接两个集合、权值最小的边,将对应顶点加入树中
  3. 重复 n-1 次,直到所有顶点加入

2. 邻接矩阵版模板(适合小规模图)

#include <iostream> #include <cstring> #include <climits> using namespace std; const int N = 1005; const int INF = 0x3f3f3f3f; int graph[N][N]; // 邻接矩阵存图 int dist[N]; // 未选点到生成树的最短距离 bool vis[N]; // 标记是否已加入生成树 int n, m; int prim() { memset(vis, false, sizeof(vis)); // 初始化距离数组 for(int i = 1; i <= n; ++i) dist[i] = graph[1][i]; vis[1] = true; // 从1号顶点开始 int sum = 0; for(int i = 1; i < n; ++i) // 还需选n-1个点 { // 找距离最小的未访问点 int minVal = INF; int pos = -1; for(int j = 1; j <= n; ++j) { if(!vis[j] && dist[j] < minVal) { minVal = dist[j]; pos = j; } } if(pos == -1) return -1; // 图不连通 sum += minVal; vis[pos] = true; // 更新剩余点到生成树的最短距离 for(int j = 1; j <= n; ++j) { if(!vis[j] && graph[pos][j] < dist[j]) dist[j] = graph[pos][j]; } } return sum; } int main() { // 矩阵初始化 memset(graph, 0x3f, sizeof(graph)); cin >> n >> m; for(int i = 1; i <= n; ++i) graph[i][i] = 0; for(int i = 0; i < m; ++i) { int u, v, w; cin >> u >> v >> w; // 无向图双向赋值,重边取最小值 if(w < graph[u][v]) { graph[u][v] = w; graph[v][u] = w; } } int res = prim(); if(res == -1) cout << "图不连通" << endl; else cout << "最小生成树总权值:" << res << endl; return 0; }

3. 特点与复杂度

  • 基础版复杂度:\(O(n^2)\)
  • 优势:适合顶点少、边稠密的图
  • 优化:可搭配优先队列(堆),优化为 \(O(m\log n)\),思路不变

五、两大算法对比 & 选型口诀

表格

算法核心依赖复杂度适用场景
Kruskal并查集 + 边排序\(O(m\log m)\)稀疏图(边少点多),刷题首选
Prim邻接矩阵 / 堆\(O(n^2)\)稠密图(边多点少)

选型口诀:点少边多用 Prim,点多边少用 Kruskal


六、今日核心总结

  1. 最小生成树:连通全顶点、n-1 条边、总权值最小、无环路。
  2. Kruskal:边排序 + 并查集判连通,稀疏图首选。
  3. Prim:以顶点为核心贪心拓展,稠密图更合适。
  4. 两个算法都基于贪心思想,遇到不连通图直接判定无解。

七、课后练习

  1. 手写 Kruskal 完整代码,结合并查集完成测试
  2. 搭建稠密图,使用 Prim 算法求解最小权值
  3. 区分两种算法的使用场景
http://www.rkmt.cn/news/1424085.html

相关文章:

  • 2026年商家小程序外卖怎么找骑手
  • 别再暴力刷新了!用ScriptableObject和事件驱动重构Unity背包系统,性能提升实测
  • 如何快速上手无名杀:免费网页版三国杀的终极体验指南
  • Raw Accel鼠标加速驱动:Windows玩家的终极鼠标响应优化方案
  • Claude市场份额暴涨217%的背后:我们访谈了43家中国企业的CTO(独家一线采购动因白皮书)
  • 别让宝贝蒙尘!丰宝斋上门回收老书旧书,唤醒时光记忆 - 深鉴新闻
  • Arm开发中的SDF文件:创建、使用与问题排查
  • 如何安全合规地管理微信数据:从PyWxDump项目下架看技术合规边界
  • 从FaceQnet v0到v1:我是如何用Python复现并改进这个人脸质量评估模型的
  • 如何快速搭建H5页面:vite-vue3-lowcode完整使用指南
  • DRV8701E双路H桥电机驱动板立创EDA工程包(含原理图PDF与PCB JSON源文件)
  • 动态规划实战:打家劫舍系列全解析
  • H3CSE 高性能园区网:NQA 网络质量分析详解
  • android跨应用截屏方案
  • Lumerical FDTD自动化脚本入门:从环境配置到第一个仿真循环(Python 3.11实测)
  • 从《超级马里奥》到你的游戏:用Unity Tilemap复刻经典FC关卡,并加入你自己的创意
  • 基于RAG与智能调度的个性化AI新闻聚合系统实践
  • Matlab Simulink中可直接运行的八字路径MPC车辆跟踪仿真(带中文注释+操作录像)
  • Android Studio入门实战:含登录注册、MD5密码保护与SQLite增删改查的学生管理系统源码
  • 论文格式改到凌晨?okbiye 智能排版实测,10 分钟搞定高校专属格式规范
  • ComfyUI-Easy-Use Get/Set节点终极修复指南:三步解决数据传递难题
  • 深入 Android 底层开发:JNI 注册机制、SO 库加载原理与安全防护策略
  • 3个实战技巧:彻底掌握ThinkPad风扇控制的静音与性能平衡
  • VSCode Mermaid插件:技术文档图表化的专业解决方案
  • Java 核心进阶:从异常处理到常用工具类
  • GitHub开源项目日报 · 2026年5月27日 · AI技能框架爆发,工具链生态成焦点
  • Claude画像标签体系崩塌前夜:3大信号预示模型老化,附72小时内紧急修复SOP(含Python自动化诊断脚本)
  • 3步解锁鸣潮自动化神器:告别重复刷本的终极方案
  • Spring Boot+Vue智慧校园系统源码包:含数据库脚本、架构图、部署文档与28张功能截图
  • WaveTools深度解析:3分钟彻底解决鸣潮120帧解锁失效问题