最短路问题的三种算法&模板
最短路算法&模板
最短路问题是图论的基础问题。本篇随笔就图论中最短路问题进行剖析,讲解常用的三种最短路算法:Floyd算法、Dijkstra算法及SPFA算法,并给出三种算法的模板。流畅阅读本篇博客需要有图论的基础知识,了解什么是图,什么是最短路,以及一些基本语法知识和算法基础。
1、Floyd算法
我个人认为,Floyd算法是三种最短路算法中最简单、最好理解的算法。它的适用范围是任意两点之间的最短路。这一点是其他两种算法(单源最短路)无法比拟的。它的实现思路也很简单:用三重循环,枚举断点、起始点和终点(注意:顺序千万不能反!!),如果起始点到断点,断点到终点的距离和小于起始点到终点当前状态下的最短路(也就是说找到了一个比它还短的),那么就更新最短路。
它的优点就是简洁明了,易于理解,但是缺点也显而易见,通过它的实现途径,我们可以发现,使用Floyd算法的题一定要用邻接矩阵存图,这样的一个二维数组显然对空间有着要求,一般来讲,只能支持不超过500个点的图,假如更多,便无法支持。同时,Floyd算法还对时间有着要求,因为是三重循环,所以它的时间复杂度是\(O(n^3)\)的,这样的复杂度如果出现在一个复杂程序中,极其容易TLE,所以,请大家使用的时候,一定要读题读题,慎重慎重!
模板:
void Floyd()
{
memset(map,0x3f,sizeof(map));
for(int i=1;i<=n;i++)
map[i][i]=0;
for(int k=1;k<=n;k++)//顺序不要反
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++)
map[i][j]=min(map[i][k]+map[k][j],map[i][j]);
}
2、Dijkstra算法
Dijkstra算法,中文名是迪杰斯特拉算法,简写是DIJ算法。DIJ算法是求解单源最短路,即从某一个源点到达其他所有点的最短路的一个经典算法。它的实现途径也很好理解:我把点分成两个集合,一个是已经扫描过的集合,另一个是没有扫描的集合。即已经确定最短路和没确定最短路的两个集合,用v数组标记。然后我们从没有扫描的集合中挑出一个dist最小的点放入已经扫描的集合中,然后从这个点开始搜索它的所有出边,进行松弛操作即可。
DIJ算法的时间复杂度比较高,大约是\(O(n^2)\)级别的,同SPFA比确实是差了一些,但它有自己独特的优势,由于它的复杂度只和点有关,所以针对于稠密图(边多点少的图),它的求解效率要比SPFA算法高很多。
关于DIJ算法可以使用二叉堆(优先队列)进行优化,即我们常说的DIJ算法堆优化,由于篇幅较长,我放到了另一篇博客中进行讲解,链接:
模板:
void dijkstra(int start)//源点
{
int temp,k,y;
memset(dist,0x3f,sizeof(dist));
memset(v,0,sizeof(v));
dist[start]=0;
for(int i=1;i<=n;i++)
{
temp=1<<30;
for(int j=1;j<=n;j++)
if(dist[j]<temp && v[j]==0)
k=j,temp=dist[j];
v[k]=1;
for(int j=head[k];j;j=nxt[j])
{
y=to[j];
if(dist[y]>dist[k]+val[j])
dist[y]=dist[k]+val[j];
}
}
}
3、SPFA算法
网上有一张热图,就是“关于SPFA,它死了”。但是SPFA并没有死,它不仅活的好好的,还是一种国产算法,更是我最擅长的最短路算法。
SPFA的适用范围同样也是单源最短路,但是它的实现途径较抽象:新建一个队列,保存等待优化的节点,把源点加入队列。取出队首节点x,遍历x的所有出边,进行松弛操作,如果x点的到达点y被更新,且y不在当前队列中,就把y压入队尾。重复直到队列空为止。
SPFA的实现模板跟宽搜很类似,希望大家好好体会。
SPFA的时间复杂度也很优越,根据证明,期望的时间复杂度可以达到\(O(kM)\),其中M为边数,k为所有顶点进队的平均次数。一般来讲,k<=2。
所以我们发现,SPFA算法适用于稀疏图,即点特别多边特别少的图。这和DIJ算法形成了一个对比,希望大家能在做题的时候活学活用。
关于SPFA的算法,有两种优化方式,由于篇幅较长,放在另一个博客中进行讲解。链接如下:
模板:
void spfa(int start)
{
memset(dist,0x3f,sizeof(dist));
memset(v,0,sizeof(v));
queue<int> q;
q.push(start);
v[start]=1;
dist[start]=0;
while(!q.empty())
{
int x=q.front();
q.pop();
v[x]=0;
for(int i=head[x];i;=nxt[i])
{
int y=to[i];
if(dist[y]>dist[x]+val[i])
{
dist[y]=dist[x]+val[i];
if(v[y]==0)
q.push(y),v[y]=1;
}
}
}
}
最短路问题的三种算法&模板的更多相关文章
- c语言求回文数的三种算法的描述
c语言求回文数的三种算法的描述 题目描述 注意:(这些回文数都没有前导0) 1位的回文数有0,1,2,3,4,5,6,7,8,9 共10个: 2位的回文数有11,22,33,44,55,66,77,8 ...
- Java利用DES/3DES/AES这三种算法分别实现对称加密
转载地址:http://blog.csdn.net/smartbetter/article/details/54017759 有两句话是这么说的: 1)算法和数据结构就是编程的一个重要部分,你若失掉了 ...
- 内存分配---FF、BF、WF三种算法
动态分区分配是根据进程的实际需要,动态的为之分配内存空间.而在实现可变分区分配时,将涉及到分区分配中 所用的数据结构.分区分配算法和分区的分配与内存回收的过程. 分区分配中的数据结构:(1)描述空闲块 ...
- 图文实例解析,InnoDB 存储引擎中行锁的三种算法
前文提到,对于 InnoDB 来说,随时都可以加锁(关于加锁的 SQL 语句这里就不说了,忘记的小伙伴可以翻一下上篇文章),但是并非随时都可以解锁.具体来说,InnoDB 采用的是两阶段锁定协议(tw ...
- 【2018寒假集训Day 7】【最短路径】三种算法的模板
Luogu单源最短路径模版题 dijkstra #include<cstdio> #include<vector> using namespace std; const int ...
- HDOJ--1869--六度分离(用三种算法写的,希望能比較出来他们之间的差别)
六度分离 Time Limit: 5000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others) Total Submi ...
- 常见算法:C语言求最小公倍数和最大公约数三种算法
最小公倍数:数论中的一种概念,两个整数公有的倍数成为他们的公倍数,当中一个最小的公倍数是他们的最小公倍数,相同地,若干个整数公有的倍数中最小的正整数称为它们的最小公倍数,维基百科:定义点击打开链接 求 ...
- C语言求最小公倍数和最大公约数三种算法(经典)
把以前写的一些经验总结汇个总,方便给未来的学弟学妹们做个参考! --------------------------永远爱你们的:Sakura 最小公倍数:数论中的一种概念,两个整数公有的倍数成为他们 ...
- 缓存算法(FIFO 、LRU、LFU三种算法的区别)
FIFO算法 FIFO 算法是一种比较容易实现的算法.它的思想是先进先出(FIFO,队列),这是最简单.最公平的一种思想,即如果一个数据是最先进入的,那么可以认为在将来它被访问的可能性很小.空间满的时 ...
随机推荐
- 安装pymssql
直接安装失败 https://www.lfd.uci.edu/~gohlke/pythonlibs/#pymssql 去下载对应的 pymssql whl版本 之后 pip install whe ...
- JavaScript基础2
本节内容: 1:ECMA对象 2:string对象 3:Array对象 4:BOM对象 5:DOM对象之节点 6:DOM对象之EVENT事件 7:DOM节点的增删改查 8: 实例练习 http://w ...
- 201871010121-王方《面向对象程序设计(Java)》第一周学习总结
项目 内容 这个作业属于哪个课程 https://www.cnblogs.com/nwnu-daizh/ 这个作业的要求在哪里 https://www.cnblogs.com/wf-001128/ 作 ...
- Mybatis框架增删改查
一.recourses中核心配置文件mybatis-config.xml 二. recourse中jdbc.properties 三.entity实体类 四.ISmbmsUserDao层 五.ISmb ...
- DFS(四):剪枝策略
顾名思义,剪枝就是通过一些判断,剪掉搜索树上不必要的子树.在采用DFS算法搜索时,有时候我们会发现某个结点对应的子树的状态都不是我们要的结果,这时候我们没必要对这个分支进行搜索,砍掉这个子树,就是剪枝 ...
- Springboot 打包自带启动脚本
一直以来,我都是 gradlew build java -jar xxx.jar 来启动springboot项目的.今天突然发现,springboot自动封装了一个bootJar的任务脚本. demo ...
- Do Deep Nets Really Need to be Deep?
url: https://arxiv.org/pdf/1312.6184.pdf year: NIPS2014 浅网络学习深网络的函数表示, 训练方法就是使用深网络的 logits(softmax i ...
- Linux Ubuntu 16.04 安装步骤+远程环境
简介 Ubantu 16.04 系统是一款比较稳定的linux系统,适合用户使用以及针对一些兼容性的服务搭建. 这里我推荐安装桌面版,用于方便使用. 准备工作 1.准备1个U盘空间5G以上 2.需下载 ...
- 公益:开放一台Nacos服务端给各位Spring Cloud爱好者
之前开放过一台公益Eureka Server给大家,以方便大家在阅读我博客中教程时候做实验.由于目前在连载Spring Cloud Alibaba,所以对应的也部署了一台Nacos,并且也开放出来,给 ...
- 从程序集加载类型,遇到 ReflectionTypeLoadException 的处理办法
处理办法 catch ReflectionTypeLoadException ,然后从里面读取 Types 数据(成功加载的类型)就可以了. 参考 ReflectionTypeLoadExceptio ...