DIJ算法的堆优化

DIJ算法的时间复杂度是\(O(n^2)\)的,在一些题目中,这个复杂度显然不满足要求。所以我们需要继续探讨DIJ算法的优化方式。

堆优化的原理

堆优化,顾名思义,就是用堆进行优化。我们通过学习朴素DIJ算法,明白DIJ算法的实现需要从头到尾扫一遍点找出最小的点然后进行松弛。这个扫描操作就是坑害朴素DIJ算法时间复杂度的罪魁祸首。所以我们使用小根堆,用优先队列来维护这个“最小的点”。从而大大减少DIJ算法的时间复杂度。

堆优化的代码实现

说起来容易,做起来难。

我们明白了上述的大体思路之后,就可以动手写这个代码,但是我们发现这个代码有很多细节问题没有处理。

首先,我们需要往优先队列中push最短路长度,但是它一旦入队,就会被优先队列自动维护离开原来的位置,换言之,我们无法再把它与它原来的点对应上,也就是说没有办法形成点的编号到点权的映射。

我们用pair解决这个问题。

pair是C++自带的二元组。我们可以把它理解成一个有两个元素的结构体。更刺激的是,这个二元组有自带的排序方式:以第一关键字为关键字,再以第二关键字为关键字进行排序。所以,我们用二元组的first位存距离,second位存编号即可。

然后我们发现裸的优先队列其实是大根堆,我们如何让它变成小根堆呢?

有两种方法,第一种是把第一关键字取相反数,取出来的时候再取相反数。第二种是重新定义优先队列:

priority_queue<int,vector<int>,greater<int> >q;

解决了这些问题,我们愉快地继续往下写,后来我们发现,写到松弛的时候,我们很显然要把松弛后的新值也压入优先队列中去,这样的话,我们又发现一个问题:优先队列中已经存在一个同样编号的二元组(即第二关键字相同),我们没有办法删去它,也没有办法更新它。那么在我们的队列和程序运行的时候,一定会出现bug。

怎么办呢??

我们在进入循环的时候就开始判断:如果有和堆顶重复的二元组,就直接pop掉,成功维护了优先队列元素的不重复。

所以我们得到了堆优化的代码:

priority_queue<pair<int,int> >q;
void dijkstra(int start)
{
memset(dist,0x3f,sizeof(dist));
memset(v,0,sizeof(v));
dist[start]=0;
q.push(make_pair(0,start));
while(!q.empty())
{
while(!q.empty() && (-q.top().first)>dist[q.top().second])
q.pop();
if(!q.empty())
return;
int x=q.top().second;
q.pop();
for(int i=head[x];i;i=nxt[i])
{
int y=to[i];
if(dist[y]>dist[x]+val[i])
{
dist[y]=dist[x]+val[i];
q.push(make_pair(-dist[y],y));
}
}
}
}

Dijkstra算法堆优化详解的更多相关文章

  1. 最短路径-迪杰斯特拉(dijkstra)算法及优化详解

    简介: dijkstra算法解决图论中源点到任意一点的最短路径. 算法思想: 算法特点: dijkstra算法解决赋权有向图或者无向图的单源最短路径问题,算法最终得到一个最短路径树.该算法常用于路由算 ...

  2. 最短路模板(Dijkstra & Dijkstra算法+堆优化 & bellman_ford & 单源最短路SPFA)

    关于几个的区别和联系:http://www.cnblogs.com/zswbky/p/5432353.html d.每组的第一行是三个整数T,S和D,表示有T条路,和草儿家相邻的城市的有S个(草儿家到 ...

  3. Dijkstra算法堆优化

    转自 https://blog.csdn.net/qq_41754350/article/details/83210517 再求单源最短路径时,算法有优劣之分,个人认为在时间方面 朴素dijkstra ...

  4. 最短路-朴素版Dijkstra算法&堆优化版的Dijkstra

    朴素版Dijkstra 目标 找到从一个点到其他点的最短距离 思路 ①初始化距离dist数组,将起点dist距离设为0,其他点的距离设为无穷(就是很大的值) ②for循环遍历n次,每层循环里找出不在S ...

  5. Dijkstra算法之 Java详解

    转载:http://www.cnblogs.com/skywang12345/ 迪杰斯特拉算法介绍 迪杰斯特拉(Dijkstra)算法是典型最短路径算法,用于计算一个节点到其他节点的最短路径. 它的主 ...

  6. $PollardRho$ 算法及其优化详解

    \(PollardRho\) 算法总结: Pollard Rho是一个非常玄学的算法,用于在\(O(n^{1/4})\)的期望时间复杂度内计算合数n的某个非平凡因子(除了1和它本身以外能整除它的数). ...

  7. Dijkstra算法堆优化(vector建图)

    #include<iostream> #include<algorithm> #include<string.h> #include<stdio.h> ...

  8. JVM垃圾回收算法及回收器详解

    引言 本文主要讲述JVM中几种常见的垃圾回收算法和相关的垃圾回收器,以及常见的和GC相关的性能调优参数. GC Roots 我们先来了解一下在Java中是如何判断一个对象的生死的,有些语言比如Pyth ...

  9. lucene、lucene.NET详细使用与优化详解

    lucene.lucene.NET详细使用与优化详解 2010-02-01 13:51:11 分类: Linux 1 lucene简介1.1 什么是luceneLucene是一个全文搜索框架,而不是应 ...

随机推荐

  1. 201871010107-公海瑜《面向对象程序设计(java)》第一周学习总结

    201871010107-公海瑜<面向对象程序设计(java)>第一周学习总结 项目 内容 这个作业属于哪个课程 https://www.cnblogs.com/nwnu-daizh/   ...

  2. dom0、dom2、dom3事件

    https://www.jianshu.com/p/3acdf5f71d5b addEventListener():可以为元素添加多个事件处理程序,触发时会按照添加顺序依次调用. removeEven ...

  3. 如何在python中使用Elasticsearch

    什么是 Elasticsearch ​ 想查数据就免不了搜索,搜索就离不开搜索引擎,百度.谷歌都是一个非常庞大复杂的搜索引擎,他们几乎索引了互联网上开放的所有网页和数据.然而对于我们自己的业务数据来说 ...

  4. Python爬虫大作业

    一.题目: 获取并保存目标网站的下图所示的所有英文名,网页转换通过点击more names刷新名字并将各个英文名子目录下,去获取并保存每一个英文名的名字.性别.寓意.简介如下图所示内容红色标记框内的内 ...

  5. js判断浏览器是否安装或启用了flash的方法总结

    目录 # js判断浏览器是否安装或启用了flash的方法 # chrome浏览器启用flash插件的方法 # 参考 # js判断浏览器是否安装或启用了flash的方法 在传统浏览器,可以使用windo ...

  6. C语言程序设计100例之(5):分解质因数

    例5    分解质因数 题目描述 将一个正整数分解质因数.例如:输入90,输出 90=2*3*3*5. 输入 输入数据包含多行,每行是一个正整数n (1<n <100000) . 输出 对 ...

  7. ubuntu 库依赖问题

    安装apt-file, 可以查找各种库依赖的文件,或查找某个app的依赖库: sudo apt install apt-file apt-file update apt-flie search rpc ...

  8. python基础(12):函数(二)

    1. 函数参数 之前我们说过了传参,如果我们需要给⼀个函数传参,⽽参数⼜是不确定的,或者我给⼀个函数传很多参数,我的形参就要写很多,很⿇烦,怎么办呢,我们可以考虑使⽤动态参数. 形参的第三种: 动态参 ...

  9. Python入门36道经典练习题

    [程序1] 题目:有1.2.3.4个数字,能组成多少个互不相同且无重复数字的三位数?都是多少? num_list=[] cou=0 for i in range(1,5): for j in rang ...

  10. JVM 参数配置

    JAVA_OPTS="-server -Xms2048m -Xmx2048m -Xmn512m -Xss256k -XX:PermSize=256m -XX:MaxPermSize=256m ...