在 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】1414. 和为 K 的最少斐波那契数字数目 Find the Minimum Number of Fibonacci Numbers Whose Sum Is K

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

  2. 第十一个知识点:DLP,CDH和DDH问题都是什么?

    第十一个知识点:DLP,CDH和DDH问题都是什么 这是第11篇也是数学背景的第二篇.主要关注群操作如何被用于设计密码基础. 就像你现在知道的那样,密码学经常依赖于'难问题'.这也就是说,如果我们假设 ...

  3. Gradient-based Hyperparameter Optimization through Reversible Learning

    目录 概 主要内容 算法 finite precision arithmic 实验 Maclaurin D, Duvenaud D, Adams R P, et al. Gradient-based ...

  4. [opencv]膨胀腐蚀

    Mat dilateimg; Mat element = getStructuringElement(MORPH_RECT, Size(3, 3)); dilate(canny, dilateimg, ...

  5. spring练习,使用Eclipse搭建的Spring开发环境,使用set注入方式为Bean对象注入属性值并打印输出。

    相关 知识 >>> 相关 练习 >>> 实现要求: 使用Eclipse搭建的Spring开发环境,使用set注入方式为Bean对象注入属性值并打印输出.要求如下: ...

  6. 【MySQL作业】MySQL函数——美和易思字符串函数应用习题

    点击打开所使用到的数据库>>> 1.将所有客户的姓名与电话以"-"作为分隔符进行连接显示. 使用 concat(s1,s2,-) 函数将所有客户的姓名与电话以&q ...

  7. 20道JavaScript经典面试题

    该篇文章整理了一些前端经典面试题,附带详解,涉及到JavaScript多方面知识点,满满都是干货-建议收藏阅读 前言 如果这篇文章有帮助到你,️关注+点赞️鼓励一下作者,文章公众号首发,关注 前端南玖 ...

  8. playwright--自动化(一):快速上手

    Playwright为现代 Web 应用程序提供可靠的端到端测试. 在JavaScript 和 TypeScript.Python..NET和Java 中都可以使用 Playwright 本人选择py ...

  9. MySQL数据库常用命令汇总

    -- 查看mysql的当前登陆用户 select user(); -- 列出数据库 show databases; -- 使用数据库 use mysql; describe mysql.user; s ...

  10. Storm对DRPC权限控制Version1.0.1

    对Storm的DRPC进行权限控制, 并且设计相应的测试验证. 1.集群安装 请参考Storm集群安装Version1.0.1 2.使用DRPC功能 请参考Storm集群使用DRPC功能Version ...