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. 【转】C++ - 结构体构造函数使用总结

    声明 转载自:https://www.cnblogs.com/wlw-x/p/11566191.html 关于结构体构造函数使用总结 三种结构体初始化方法 1.利用结构体自带的默认构造函数 2.利用带 ...

  2. python操作队列

    进行队列的操作,首先要引入queue这个库 一:设置队列(括号中是队列可容纳数据的多少,如果不设置,则可以一直增加) import queue q = queue.Queue(10) 二:添加/获取元 ...

  3. acwing 600. 仰视奶牛

    题目地址  https://www.acwing.com/problem/content/description/602/ 约翰有N头奶牛,编号为1到N. 现在这N头奶牛按编号从小到大的顺序站成了一排 ...

  4. 【AtCoder】AtCoder Grand Contest 040 解题报告

    点此进入比赛 \(A\):><(点此看题面) 大致题意: 给你一个长度为\(n-1\).由\(<\)和\(>\)组成的的字符串,第\(i\)位的字符表示第\(i\)个数和第\( ...

  5. Python程序中的进程操作-进程同步(multiprocess.Lock)

    目录 一.多进程抢占输出资源 二.使用锁维护执行顺序 三.多进程同时抢购余票 四.使用锁来保证数据安全 通过刚刚的学习,我们千方百计实现了程序的异步,让多个任务可以同时在几个进程中并发处理,他们之间的 ...

  6. .NET 时间轴:从出生到巨人

    自1995年互联网战略日以来最雄心勃勃的事业 —— 微软.NET战略, 2000年6月30日. 微软于2000年推出基于Windows操作系统的应用软件开发框架.NET,发展至今形成巨大的技术栈,涉及 ...

  7. 解决root用户下都无权限操作的问题

    问题现象: 有时系统设置了一种文件,无法编辑其所有权​ sudo chown users:username {filename} 或者root用户下执行 chown users:username {f ...

  8. python 动态语言和协议编程

    动态语言:不需要去定义变量的类型 协议编程:一个类实现了某个魔法函数,这个类就是什么类型,理解为协议

  9. Android高可用移动网络连接---(转载自http://wingjay.com/2019/01/16/mobile-network-connection/)

    读者好,前面我们在 <Android 架构之网络连接与加速> 和<Android 架构之长连接技术>两篇文章中,讲解了 Http 短连接.TCP 长连接.连接复用与速度优化.数 ...

  10. TCP协议 - 可靠性

    在前篇文章中介绍了TCP协议的三大特性,其中可靠性是依赖一系列的机制,如:校验和,分组发送,超时重传,流量控制得到保证. 一.数据交互 TCP在交互数据时,采用多种机制保证可靠性,同时也保证TCP的性 ...