在 Prim 算法中使用 pb_ds 堆优化

Prim 算法用于求最小生成树(Minimum Spanning Tree,简称 MST),其本质是一种贪心的加点法。对于一个各点相互连通的无向图而言,Prim 算法的具体步骤如下:

令 \(G=(V,E)\) 表示原图,\(G'=(V',E')\) 表示 \(G\) 的最小生成树,\(dis_u\) 表示节点 \(u\) 到任意 \(v \in V'\) 的最小距离(初始化为 \(+\infty\))。

  1. 任取节点\(s \in V\),令 \(dis_s=0\);
  2. 找到一个节点 \(u \in \complement_V V'\),使得 \(dis_u\) 最小;
  3. 将 \(u\) 加入 \(V'\),\(dis_u\) 所代表的边加入 \(E'\);
  4. 对于任意边 \((u,v)\in \complement_E E'\),令 \(dis_v=\min \{dis_v,w\}\),其中 \(w\) 为边 \((u,v)\) 的权值;
  5. 重复过程 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 堆优化的更多相关文章

  1. 一步一步写算法(之prim算法 中)

    原文:一步一步写算法(之prim算法 中) [ 声明:版权所有,欢迎转载,请勿用于商业用途.  联系信箱:feixiaoxing @163.com] C)编写最小生成树,涉及创建.挑选和添加过程 MI ...

  2. Dijkstra算法的二叉堆优化

    Dijkstra算法的二叉堆优化 算法原理 每次扩展一个距离最小的点,再更新与其相邻的点的距离. 如何寻找距离最小的点 普通的Dijkstra算法的思路是直接For i: 1 to n 优化方案是建一 ...

  3. 最短路径——Dijkstra算法以及二叉堆优化(含证明)

    一般最短路径算法习惯性的分为两种:单源最短路径算法和全顶点之间最短路径.前者是计算出从一个点出发,到达所有其余可到达顶点的距离.后者是计算出图中所有点之间的路径距离. 单源最短路径 Dijkstra算 ...

  4. 图论——最小生成树:Prim算法及优化、Kruskal算法,及时间复杂度比较

    最小生成树: 一个有 n 个结点的连通图的生成树是原图的极小连通子图,且包含原图中的所有 n 个结点,并且有保持图连通的最少的边.简单来说就是有且仅有n个点n-1条边的连通图. 而最小生成树就是最小权 ...

  5. 求最小生成树(暴力法,prim,prim的堆优化,kruskal)

    求最小生成树(暴力法,prim,prim的堆优化,kruskal) 5 71 2 22 5 21 3 41 4 73 4 12 3 13 5 6 我们采用的是dfs的回溯暴力,所以对于如下图,只能搜索 ...

  6. Dijkstra算法堆优化详解

    DIJ算法的堆优化 DIJ算法的时间复杂度是\(O(n^2)\)的,在一些题目中,这个复杂度显然不满足要求.所以我们需要继续探讨DIJ算法的优化方式. 堆优化的原理 堆优化,顾名思义,就是用堆进行优化 ...

  7. 算法8-5:Prim算法

    Prim算法用于计算最小生成树.Prim算法分为两种,一种是懒汉式,一种是饿汉式. 懒汉式Prim 懒汉式Prim算法过程例如以下: 首先将顶点0增加到MST中 从MST与未訪问顶点之间边中选出最短的 ...

  8. Dijkstra和Prim算法的区别

    Dijkstra和Prim算法的区别 1.先说说prim算法的思想: 众所周知,prim算法是一个最小生成树算法,它运用的是贪心原理(在这里不再证明),设置两个点集合,一个集合为要求的生成树的点集合A ...

  9. 算法导论--最小生成树(Kruskal和Prim算法)

    转载出处:勿在浮沙筑高台http://blog.csdn.net/luoshixian099/article/details/51908175 关于图的几个概念定义: 连通图:在无向图中,若任意两个顶 ...

随机推荐

  1. 【LeetCode】104. Maximum Depth of Binary Tree 解题报告(Python)

    作者: 负雪明烛 id: fuxuemingzhu 个人博客: http://fuxuemingzhu.cn/ 目录 题目描述 题目大意 解题方法 方法一:BFS 方法二:DFS 参考资料 日期 题目 ...

  2. 【LeetCode】447. Number of Boomerangs 解题报告(Java & Python)

    作者: 负雪明烛 id: fuxuemingzhu 个人博客: http://fuxuemingzhu.cn/ 目录 题目描述 题目大意 解题方法 日期 [LeetCode] 题目地址:https:/ ...

  3. 【LeetCode】274. H-Index 解题报告(Python)

    作者: 负雪明烛 id: fuxuemingzhu 个人博客: http://fuxuemingzhu.cn/ 题目地址: https://leetcode.com/problems/h-index/ ...

  4. Lotus and Horticulture

    Lotus and Horticulture Accepts: 91 Submissions: 641 Time Limit: 4000/2000 MS (Java/Others) Memory Li ...

  5. 【LeetCode】767. Reorganize String 解题报告(Python)

    作者: 负雪明烛 id: fuxuemingzhu 个人博客: http://fuxuemingzhu.me/ 题目地址:https://leetcode.com/problems/reorganiz ...

  6. Interesting Yang Yui Triangle(hdu3304)

    Interesting Yang Yui Triangle Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K ...

  7. python学习第四天:python基础(字符编码和乱码到底咋回事儿)

    字符编码 这得从字符编码开始说起: 字符串也是一种数据类型,但是,字符串比较特殊的是还有一个编码问题.因为计算机只能处理数字,如果要处理文本,就必须先把文本转换为数字才能处理. 最早的计算机在设计时采 ...

  8. IntelliJ IDEA打war包

    1.按ctrl+alt+shift+s键打开Project Structure,点击+号图标,选择"Artifacts->Web Application Archive" 2 ...

  9. Inverse/Implicit Function Theorem

    目录 4.1 The Inverse Function Theorem The Implicit Function Theorem 4.3 Curves and Surfaces 4.4 The Mo ...

  10. Java语言程序设计复习提纲

     这是我在准备Java考试时整理的提纲,如果是通过搜索引擎搜索到这篇博客的师弟师妹,建议还是先参照PPT和课本,这个大纲也不是很准确,自己总结会更有收获,多去理解含义,不要死记硬背,否则遇到概念辨析题 ...