上期回顾:https://www.cnblogs.com/ofnoname/p/18715203

在前文中,我们剖析了最小生成树(MST)问题中的两大经典算法:

  • Kruskal 以“边权平等”为信条,通过排序与并查集自下而上聚合连通分量;
  • Prim 以“中心辐射”为策略,通过优先队列自上而下扩张领土。

二者虽路径迥异,却殊途同归,均以贪心策略保证全局最优。还有一种不那么为人熟知的 Sollin 算法(又称 Boruvka 算法),它融合了前两者的思想,并在并行计算领域大放异彩,在特定情况下非常有用。

Sollin 算法:分治与并行

Sollin 算法仍然基于贪心,但是他从多个起点开始。想象一场战国时代的争霸赛:初始每一个点都是一代表一个国家,自身是一个连通分量,接下来每个小国(连通分量)各自派出使者,寻找与邻国间成本最低的结盟道路。所有国家同时行动,每一轮合并后形成更大的联盟,直到天下归一。Sollin 算法的核心正是这种分阶段的并行贪心策略

具体步骤

  1. 初始化:每个节点自成一个连通分量。
  2. 并行探索:每一轮迭代下,对每个连通分量,找到其连接外界的最小权重边(类似 Prim 的切割性质)。
  3. 批量合并:将所有找到的最小边加入 MST,合并连通分量。
  4. 循环迭代:重复步骤 2-3,直至只剩一个连通分量。

正确性证明

Sollin 的正确性同样基于安全边定理

每个连通分量选择的最小出边,必定属于某个 MST。

归纳法视角

  • 初始状态:每个节点独立,所有边均为安全边候选。
  • 归纳假设:当前已选边集是某个 MST 的子集。
  • 归纳步骤:每轮选择的边均为不同切割的最小边,加入后仍保持 MST 的存在性。

关键观察

  • 若两个连通分量选择彼此之间的同一条边,该边只会被加入一次(去重机制)。
  • 合并操作保证连通分量数量至少减半,确保算法终止。
struct Edge {
int u, v, weight, index;
}; class Graph {
int n, m;
vector<Edge> edges; public:
Graph(int n, int m) : n(n), m(m) {} void addEdge(int u, int v, int weight, int index) {
edges.push_back({u, v, weight, index});
} long long boruvka(vector<int>& result) {
UnionFind uf(n); // 并查集实现略
long long total_weight = 0;
int components = n; while (components > 1) {
vector<Edge> min_edges(n, {-1, -1, INT_MAX, -1}); // 查找每个连通分量的最小边
for (const auto& edge : edges) {
int root_u = uf.find(edge.u);
int root_v = uf.find(edge.v);
if (root_u == root_v) continue; if (edge.weight < min_edges[root_u].weight)
min_edges[root_u] = edge; if (edge.weight < min_edges[root_v].weight)
min_edges[root_v] = edge;
} // 收集并处理有效边
unordered_set<int> valid_edges;
for (int i = 0; i < n; ++i) {
if (min_edges[i].index != -1 &&
!uf.connected(min_edges[i].u, min_edges[i].v)) {
valid_edges.insert(min_edges[i].index);
}
} if (valid_edges.empty()) break; // 合并连通分量并记录结果
int added = 0;
for (int idx : valid_edges) {
const Edge& e = edges[idx];
if (uf.unite(e.u, e.v)) {
total_weight += e.weight;
result.push_back(idx);
added++;
}
} if (added == 0) break;
components -= added;
} return components == 1 ? total_weight : -1;
}
};

时间复杂度

  • 每轮操作成本

    • 寻找每个连通分量的最小边:\(O(|E|)\)(需遍历所有边)。
    • 合并连通分量:使用并查集优化后接近 \(O(|V| \cdot \alpha(|V|))\)。
  • 轮数上限:由于每轮连通分量数量至少减半,总轮数为 \(O(\log |V|)\)。
  • 总复杂度:\(O(|E| \log |V|)\),与二叉堆优化的 Prim 算法相当。

Sollin vs Kruskal

维度 Sollin (Boruvka) Kruskal
核心策略 多连通分量并行找最小边 全局排序 + 单线程并查集
时间复杂度 \(O(|E| \log |V|)\) \(O(|E| \log |E|)\)
空间复杂度 需维护多个连通分量 只需存储并查集和边列表
并行潜力 每轮操作天然可并行(如MapReduce) 排序和并查集依赖全局状态
适用场景 边权分布均匀的图,或需要并行处理 稀疏图(\(|E| \ll |V|^2\))
实现难度 较高(需处理多分量合并与去重) 简单(仅排序与并查集)

在分布式系统中,每轮各连通分量的最小边搜索可分配给不同计算节点,适合超大规模图(如社交网络分析)。据说 Boruvka 算法在 20 世纪 20 年代被用于规划捷克斯洛伐克的电力网络,其分阶段特性契合人工计算流程。

最小生成树可并行化的 Sollin(Boruvka)算法的更多相关文章

  1. 最小生成树--Prim算法,基于优先队列的Prim算法,Kruskal算法,Boruvka算法,“等价类”UnionFind

    最小支撑树树--Prim算法,基于优先队列的Prim算法,Kruskal算法,Boruvka算法,“等价类”UnionFind 最小支撑树树 前几节中介绍的算法都是针对无权图的,本节将介绍带权图的最小 ...

  2. 洛谷P3366 【模板】最小生成树(Boruvka算法)

    题意 题目链接 Sol 自己yy着写了一下Boruvka算法. 算法思想很简单,就是每次贪心的用两个联通块之间最小的边去合并. 复杂度\(O(n \log n)\),然鹅没有Kruskal跑的快,但是 ...

  3. MST最小生成树及Prim普鲁姆算法

    MST在前面学习了Kruskal算法,还有一种算法叫做Prim的.这两者的区别是Prim算法适合稠密图,比如说鸟巢这种几乎所有点都有相连的图.其时间复杂度为O(n^2),其时间复杂度与边的数目无关:而 ...

  4. 【数据结构】 最小生成树(四)——利用kruskal算法搞定例题×3+变形+一道大水题

    在这一专辑(最小生成树)中的上一期讲到了prim算法,但是prim算法比较难懂,为了避免看不懂,就先用kruskal算法写题吧,下面将会将三道例题,加一道变形,以及一道大水题,水到不用高级数据结构,建 ...

  5. 【数据结构】最小生成树之prim算法和kruskal算法

    在日常生活中解决问题经常需要考虑最优的问题,而最小生成树就是其中的一种.看了很多博客,先总结如下,只需要您20分钟的时间,就能完全理解. 比如:有四个村庄要修四条路,让村子能两两联系起来,这时就有最优 ...

  6. 最小生成树——Kruskal(克鲁斯卡尔)算法

    [0]README 0.1) 本文总结于 数据结构与算法分析, 源代码均为原创, 旨在 理解 Kruskal(克鲁斯卡尔)算法 的idea 并用 源代码加以实现: 0.2)最小生成树的基础知识,参见 ...

  7. hiho一下 第二十九周 最小生成树三·堆优化的Prim算法【14年寒假弄了好长时间没搞懂的prim优化:prim算法+堆优化 】

    题目1 : 最小生成树三·堆优化的Prim算法 时间限制:10000ms 单点时限:1000ms 内存限制:256MB 描述 回到两个星期之前,在成功的使用Kruscal算法解决了问题之后,小Ho产生 ...

  8. 【甘道夫】并行化频繁模式挖掘算法FP Growth及其在Mahout下的命令使用

    今天调研了并行化频繁模式挖掘算法PFP Growth及其在Mahout下的命令使用,简单记录下试验结果,供以后查阅: 环境:Jdk1.7 + Hadoop2.2.0单机伪集群 +  Mahout0.6 ...

  9. Boruvka算法求最小生成树

    学习了一个新的最小生成树的算法,Boruvka(虽然我不知道怎么读).算法思想也是贪心,类似于Kruskal. 大致是这样的,我们维护图中所有连通块,然后遍历所有的点和边,找到每一个连通块和其他连通块 ...

  10. 最小生成树之 prim算法和kruskal算法(以 hdu 1863为例)

    最小生成树的性质 MST性质:设G = (V,E)是连通带权图,U是V的真子集.如果(u,v)∈E,且u∈U,v∈V-U,且在所有这样的边中, (u,v)的权c[u][v]最小,那么一定存在G的一棵最 ...

随机推荐

  1. vmware ESXi快速创建新的虚拟机

    ​准备工作:新虚拟机Win10 安装后,需要windows update,更新补丁到最新,关机.(本文案例win10-Amadeus) 在数据盘新建Win10-Users文件夹(可自定义) 复制win ...

  2. GooseFS 在云端数据湖存储上的降本增效实践

    ​ | 导语 基于云端对象存储的大数据和数据湖存算分离场景已经被广泛铺开,计算节点的独立扩缩容极大地优化了系统的整体运行和维护成本,云端对象存储的无限容量与高吞吐也保证了计算任务的高效和稳定.然而,云 ...

  3. showModalBottomSheet setState 无法更新ui和高度设置问题

    showModalBottomSheet setState 无法更新ui问题 首先理解showModalBottomSheet,本质上可以理解为路由入栈,在show之后弹出的页面其实是另一个页面了,此 ...

  4. 【Vue】Vue脚手架安装搭建

    ## Vue脚手架安装搭建 操作系统:Windows 11 专业工作站 记录时间:2022年2月18日 在安装之前,需要安装node.js(Node.js (nodejs.org)),否则无法使用np ...

  5. Qt/C++视频监控拉流显示/各种rtsp/rtmp/http视频流/摄像头采集/视频监控回放/录像存储

    一.前言 本视频播放组件陆陆续续写了6年多,一直在持续更新迭代,视频监控行业客户端软件开发首要需求就是拉流显示,比如给定一个rtsp视频流地址,你需要在软件上显示实时画面,其次就是录像保存,再次就是一 ...

  6. Qt编译数据库插件通用步骤说明

    近期特意花了点时间,在之前数据库集成应用这个组件的基础上再次迭代完善,历经九九八十一难,将Qt的各种数据库插件,十几个Qt版本,全部编译一遍,同时打通了插件形式直连数据库和ODBC数据源连接方式,做过 ...

  7. Qt开源作品44-超级曲线图表

    按照国际惯例,先吹吹牛,QCustomPlot这个开源图表组件,作者绝对是全宇宙Qt领域的天花板,设计的极其巧妙和精美,各种情况都考虑到了,将每个功能细分到不同的类,每个类负责管理自己的绘制和各种属性 ...

  8. Qt编写百度地图综合应用(在线+离线+区域)

    一.前言 在现在很多的应用系统中,会提供一个地图模块,地图相关的应用和app也是非常多,最广泛的应用就属于导航,地图基本上分在线的和离线的两种,在线的一般都是实时的,数据也是最新的,速度很快路线很准, ...

  9. Qt编写地图综合应用20-多浏览器内核

    一.前言 本人写Qt程序这么多年,比较喜欢支持多个Qt版本,尤其是钟情于支持任意Qt版本+任意系统+任意编译器,这句话说起来简单其实实现起来就不容易了,首先你得有个很多版本的测试环境,起码十几个Qt环 ...

  10. rysnc使用手册

    rsync 是一个用于在本地和远程计算机之间同步文件和目录的命令行工具.它具有许多强大的功能,包括增量传输.压缩和保留权限等.以下是一些 rsync 的常用选项和用法示例: 基本用法 rsync [O ...