三个最短路径算法Dijsktra, Floyd, SPFA的总结

刚做完算法作业,好久没碰算法了,这里回顾一下最短路径中比较经典的算法:Dijsktra,Floyd,SPFA


Dijsktra

解决的是单源最短路径的问题

贪心的思想。

且贪心的依据,也正是算法中最关键的一点,当前已知source到所有未确定最短路径的节点的路径中,最短的那一个一定是source出发到该节点最短路径。dist数组存放source到其他节点当前的最短路径。S集合存放了从source出发的所有确定了最终最短路径的节点,D集合存放还未确定全局最短路径的节点。

首先,Dijsktra的更新方式,是每次新加入一个节点,都去更新dist数组,所以这也就涵盖了从source出发经过S中的节点到达某一个D中节点的路径是最短路径的可能,因此不用担心这种方式只考虑了从source出发直接连接到D中节点的问题,因为并不是如此,他实际上考虑了source出发经过S中节点到D中节点的路径长度。这是一个不断积累的过程。因此不用担心这种更新方式会错过从source出发经过S中节点到达某一个D中节点的路径是最短路径的情况;

其次,贪心的依据,由dijsktra更新方式可知,当前dist数组中存放的路径长度都是涵盖了从source出发经过S集合中顶点到D集合中某一个顶点的路径。这里存在归纳的思想,我们只需要考虑某一个阶段即可。

设现在处于第i个更新阶段。我们只需关注D中的节点,找到dist中从source到D中某一个节点Dj具有最短的路径,加入S,贪心的过程完成。为什么可以这么做呢?D中最短的路径对应的节点为Dj,而D中其他的某一节点为Dk,有dist[Dj]<dist[Dk]:

从source出发经过S中的某些节点到达Dj的路径一定会比从source出发经过S中的某些节点到达Dk再从Dk到达Dj的路径更小,因为:

从source出发经过S中的某些节点到达Dj的路径=dist[Dj];

从source出发经过S中的某些节点到达Dk的路径=dist[Dk];

我们已知dist[Dj]<dist[Dk],所以更不用说dist[Dj]<dist[Dk]+distance[Dk->Dj]了。

所以如果我们回到一开始的情况,只有一个source,很明显,我们能首先确定的一定是当前source能直接连接到的所有节点中路径最短的节点Dx对应的路径是一个最短路径,而其他的节点Dl,有可能有source出发经过Dx再到Dl存在一个最短路径,只要distance[source, Dl]>distance[source, Dx]+distance[Dx, Dl]。因为

distance[source, Dl]<distance[source, Dx],且当前distance[Dx, Dl]未知(还没有对其进行考虑),所以这种情况是有可能的。但是正如上述分析,我们现在能确定的就是Dx的最短路径。

由此,归纳过程已完成,证明也完成了。

所以当前能确定下来的就是Dj应该是当前确定下最短路径的节点,即即将成为S中的一员。


Floyd

Floyd解决的是任意两个节点之间的最短路径,所以并不像单源最短路径那样,给出了一个source,而是你需要去考虑所有的节点的情况。那么可想而知,存储dist的不能够再是一个一维数组了,而应该是一个matrix。

矩阵dist中的元素dist[i][j]存储graph中顶点i到顶点j的最短路径。所以我们需要做的就是去更新这个dist矩阵。由于是任意两个节点,所以我们需要对所有的节点都给予考虑。同时,为了能够较好地得到最短路径,我们还需要额外的一个数组,来存储到达某一个节点的最短路径额前一个路径,由此来确定整个最短路径经过的节点。即另这个矩阵为path,其中path[i][j]表示节点i到节点j的最短路径的路径上,i->…->j路径中,到达j的前一个节点的index。所以只需要不断往前找path中的值,就可以得到整个最短路径依次经过的节点。这里实际上是一个递归的思想。

所以,假设现在有N个节点,对应的dist和path矩阵都是N x N的矩阵。我们现在要做的,就是进行N次对dist和path中元素的更新。每一次使用一个节点Nx,通过向所有路径中倒数第二个节点位置插入这个节点Nx后,看看能否获得一个更短的路径,以此来更新dist和path矩阵。


SPFA

解决的是单源最短路径问题。

这里实际上有BFS的含义,但是和Dijsktra类似,只不过这里使用一个queue来辅助更新的过程,可以理解为完成BFS。每次只将有路径更新的节点的出度节点加入queue中,如果出度为零或者该节点并没有对路径的最小化提供贡献,着其出度节点不会加入queue中完成下一轮迭代。如果不这样整个过程将没有止境。

所以循环的条件就是queue为空。


参考资料:https://blog.csdn.net/qq_35644234/article/details/60870719

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值