在 Prim 算法中使用 pb_ds 堆优化
在 Prim 算法中使用 pb_ds 堆优化
Prim 算法用于求最小生成树(Minimum Spanning Tree,简称 MST),其本质是一种贪心的加点法。对于一个各点相互连通的无向图而言,Prim 算法的具体步骤如下:
令 \(G=(V,E)\) 表示原图,\(G'=(V',E')\) 表示 \(G\) 的最小生成树,\(dis_u\) 表示节点 \(u\) 到任意 \(v \in V'\) 的最小距离(初始化为 \(+\infty\))。
- 任取节点\(s \in V\),令 \(dis_s=0\);
- 找到一个节点 \(u \in \complement_V V'\),使得 \(dis_u\) 最小;
- 将 \(u\) 加入 \(V'\),\(dis_u\) 所代表的边加入 \(E'\);
- 对于任意边 \((u,v)\in \complement_E E'\),令 \(dis_v=\min \{dis_v,w\}\),其中 \(w\) 为边 \((u,v)\) 的权值;
- 重复过程 2 到 过程 4,直到 \(V'=V\)。

该算法的正确性证明可以参考 OI Wiki。
朴素的 Prim 算法时间复杂度为 \(O(n^2+m)\),其中大部分时间都消耗在操作 2 上,可以考虑利用堆对其进行优化。用二叉堆等不支持 \(O(1)\) decrease-key 操作的堆优化后时间复杂度为 \(O((n+m)\log n)\),用 Fibonacci 堆优化后的时间复杂度为 \(O(n \log n+m)\)(参考 OI Wiki)。相较于 Kruskal 算法,Prim 算法在稠密图上的效率更高。
Prim 算法中大量使用到 decrease-key 操作。在 OI 竞赛中,为节约时间,可以使用 C++ 标准库中封装好的数据结构代替手写堆。由于 std::priority_queue 不支持 decrease-key 操作,常常用 std::map 代替。实际上,std::set 内部实现是一棵常数较大的红黑树,这种用法显然会影响运行效率。鉴于当前 OI 竞赛中几乎全部采用 GNU 编译器,且 CCF 已经明确允许使用 pb_ds,我们可以使用 __gnu_pbds::priority_queue 作为堆来优化 Prim 算法,可以选择不同种类的堆作为内部实现,其中最快也是默认的是 配对堆(Pairing Heap)。具体使用方式见代码模板:
#include <bits/extc++.h>
using namespace std;
const int maxn = 5005;
const int inf = 0x3f3f3f3f;
int n, m;
vector<pair<int, int>> g[maxn];
__gnu_pbds::priority_queue<pair<int, int>, greater<>> heap;
__gnu_pbds::priority_queue<pair<int, int>, greater<>>::point_iterator p[maxn]; // dis[i] and iterator for decrease-key
int prim() {
int ans = 0;
p[1] = heap.push(make_pair(0, 1));
for (int i = 2; i <= n; ++i)
p[i] = heap.push(make_pair(inf, i));
while (!heap.empty()) {
if (heap.top().first == inf)
return -1;
int u = heap.top().second;
ans += heap.top().first;
heap.pop();
p[u] = heap.end();
for (auto& i : g[u])
if (p[i.first] != heap.end() && i.second < p[i.first]->first)
heap.modify(p[i.first], make_pair(i.second, i.first));
}
return ans;
}
int main() {
ios::sync_with_stdio(false);
cin.tie(nullptr);
cin >> n >> m;
for (int i = 1; i <= m; ++i) {
int u, v, w;
cin >> u >> v >> w;
g[u].emplace_back(v, w);
g[v].emplace_back(u, w);
}
int ans = prim();
if (ans != -1)
cout << ans << endl;
else
cout << "orz" << endl;
return 0;
}
转载请注明出处。原文地址:https://www.cnblogs.com/na-sr/p/clang-format.html
在 Prim 算法中使用 pb_ds 堆优化的更多相关文章
- 一步一步写算法(之prim算法 中)
原文:一步一步写算法(之prim算法 中) [ 声明:版权所有,欢迎转载,请勿用于商业用途. 联系信箱:feixiaoxing @163.com] C)编写最小生成树,涉及创建.挑选和添加过程 MI ...
- Dijkstra算法的二叉堆优化
Dijkstra算法的二叉堆优化 算法原理 每次扩展一个距离最小的点,再更新与其相邻的点的距离. 如何寻找距离最小的点 普通的Dijkstra算法的思路是直接For i: 1 to n 优化方案是建一 ...
- 最短路径——Dijkstra算法以及二叉堆优化(含证明)
一般最短路径算法习惯性的分为两种:单源最短路径算法和全顶点之间最短路径.前者是计算出从一个点出发,到达所有其余可到达顶点的距离.后者是计算出图中所有点之间的路径距离. 单源最短路径 Dijkstra算 ...
- 图论——最小生成树:Prim算法及优化、Kruskal算法,及时间复杂度比较
最小生成树: 一个有 n 个结点的连通图的生成树是原图的极小连通子图,且包含原图中的所有 n 个结点,并且有保持图连通的最少的边.简单来说就是有且仅有n个点n-1条边的连通图. 而最小生成树就是最小权 ...
- 求最小生成树(暴力法,prim,prim的堆优化,kruskal)
求最小生成树(暴力法,prim,prim的堆优化,kruskal) 5 71 2 22 5 21 3 41 4 73 4 12 3 13 5 6 我们采用的是dfs的回溯暴力,所以对于如下图,只能搜索 ...
- Dijkstra算法堆优化详解
DIJ算法的堆优化 DIJ算法的时间复杂度是\(O(n^2)\)的,在一些题目中,这个复杂度显然不满足要求.所以我们需要继续探讨DIJ算法的优化方式. 堆优化的原理 堆优化,顾名思义,就是用堆进行优化 ...
- 算法8-5:Prim算法
Prim算法用于计算最小生成树.Prim算法分为两种,一种是懒汉式,一种是饿汉式. 懒汉式Prim 懒汉式Prim算法过程例如以下: 首先将顶点0增加到MST中 从MST与未訪问顶点之间边中选出最短的 ...
- Dijkstra和Prim算法的区别
Dijkstra和Prim算法的区别 1.先说说prim算法的思想: 众所周知,prim算法是一个最小生成树算法,它运用的是贪心原理(在这里不再证明),设置两个点集合,一个集合为要求的生成树的点集合A ...
- 算法导论--最小生成树(Kruskal和Prim算法)
转载出处:勿在浮沙筑高台http://blog.csdn.net/luoshixian099/article/details/51908175 关于图的几个概念定义: 连通图:在无向图中,若任意两个顶 ...
随机推荐
- 【LeetCode】320. Generalized Abbreviation 解题报告 (C++)
作者: 负雪明烛 id: fuxuemingzhu 个人博客:http://fuxuemingzhu.cn/ 目录 题目描述 题目大意 解题方法 DFS 日期 题目地址:https://leetcod ...
- 【九度OJ】题目1187:最小年龄的3个职工 解题报告
[九度OJ]题目1187:最小年龄的3个职工 解题报告 标签(空格分隔): 九度OJ http://ac.jobdu.com/problem.php?pid=1187 题目描述: 职工有职工号,姓名, ...
- 【LeetCode】609. Find Duplicate File in System 解题报告(Python & C++)
作者: 负雪明烛 id: fuxuemingzhu 个人博客: http://fuxuemingzhu.cn/ 目录 题目描述 题目大意 解题方法 日期 题目地址:https://leetcode.c ...
- 一个老菜鸟的年度回忆 & 智能工厂奋斗的第三年,可能有你值得借鉴的
岁月蹉跎,寒冬的夜晚仍伏案疾书,见论坛中有诸多大神已经开始了一年的总结,突然安奈不住心中的躁动,也想为这今年的奋斗留下只言片语,没有年初的目标总结,没有未来的展望,就想作为一篇日记记录今年项目精力,为 ...
- <学习opencv>opencv函数
/*=========================================================================*/ // openCV中的函数 /*====== ...
- 搞一下vue生态,从vuex开始
Vuex vuex 是专门帮助vue管理的一个js库,利用了vue.js中细粒度数据响应机制来进行高效的状态更新. vuex核心就是store,store就是个仓库,这里采用了单一的store状态树, ...
- 『无为则无心』Python函数 — 29、Python变量和参数传递
目录 1.Python的变量 (1)Python变量不能独立存在 (2)变量是内存中数据的引用 (3)注意点 2.了解变量的引用 3.Python的参数传递(重点) (1)示例 (2)结论 (3)总结 ...
- Git 远程分支常用操作
# 查看远程仓库推拉地址,分支信息,分支跟踪情况等 git remote show origin # 拉取远程仓库的变更内容到本地 git fetch origin # 拉取并合并仓库的变更内容到本地 ...
- 初识python:hello world 仪式感
python print 函数(在python中,不区分 ' ' 和 " "): print('hello world') 或者 print("hello wrold& ...
- Selenium_环境安装(1)
Selenium是一个用于Web应用程序自动化测试工具.Selenium测试直接运行在浏览器中,就像真正的用户在操作一样. Selenium基本上支持主流的浏览器,包括IE,Mozilla Firef ...