最短路问题的三种算法&模板
最短路算法&模板
最短路问题是图论的基础问题。本篇随笔就图论中最短路问题进行剖析,讲解常用的三种最短路算法: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,队列),这是最简单.最公平的一种思想,即如果一个数据是最先进入的,那么可以认为在将来它被访问的可能性很小.空间满的时 ...
随机推荐
- MYSQL 命令导出事件、存储过程、触发器
普通导出某个数据库 mysqldump -u username -p passowrd databasename > file.sql 顺便导出事件 使用 –events 参数 mysqldum ...
- 201871010121-王方《面向对象程序设计(Java)》第一周学习总结
项目 内容 这个作业属于哪个课程 https://www.cnblogs.com/nwnu-daizh/ 这个作业的要求在哪里 https://www.cnblogs.com/wf-001128/ 作 ...
- 《算法问题实战策略》 BOGGLE
oj地址是韩国网站 连接比较慢 https://algospot.com/judge/problem/read/BOGGLE大意如下 输入输出 输入 URLPM XPRET GIAET XTNZY X ...
- javaee和javase的区别
JavaEE是指Java Enterprise Edition,Java企业版,多用于企业级开发,包括web开发等等.也叫J2EE. JavaSE通常是指Java Standard Edition,J ...
- 基于SincNet的原始波形说话人识别
speaker recognition from raw waveform with SincNet Mirco Ravanelli, Yoshua Bengio 作为一种可行的替代i-vector的 ...
- Java反射方法总结
1.得到构造器的方法 Constructor getConstructor(Class[] params) -- 获得使用特殊的参数类型的公共构造函数, Constructor[] getConstr ...
- 拎壶学python3-----(2)python之if语句用法
在生活中我们经常遇到各种选择,比如玩色子,猜大小,再比如选择未来另一半.python也经常会遇到这样的选择,这时候if语句显得尤为重要. 下边我们看一个简单的例子 如果是二选一怎么做呢?如下 如果多个 ...
- 依赖注入在 dotnet core 中实现与使用:2 使用 Extensions DependencyInjection
既然是依赖注入容器,必然会涉及到服务的注册,获取服务实例,管理作用域,服务注入这四个方面. 服务注册涉及如何将我们的定义的服务注册到容器中.这通常是实际开发中使用容器的第一步,而容器本身通常是由框架来 ...
- 黄聪:不使用 webpack,vuejs 异步加载模板
webpack 打包不会玩,整了这么个小玩具 一段 vue 绑定代码,关键点在 gmallComponent 1.异步加载外部 vue 文件(非 .vue) 2.按一定规则拆分 template.sc ...
- 程序卡在 while(SPI_I2S_GetFlagStatus(W5500_SPI, SPI_I2S_FLAG_TXE) == RESET) 处
stm32 SPI1,发现程序卡在 while(SPI_I2S_GetFlagStatus(W5500_SPI, SPI_I2S_FLAG_TXE) == RESET); 解决方式: 1.检查RCC时 ...