基本最短路算法的分析和比较

1.Floyd算法(求任意两点最短路径,不能解决含有负权回路的图)

核心代码:


for (int k=1; k<=n; k++) {//最外层循环必须是枚举松弛点,每枚举一个松弛点i到j距离都会缩短.假设1to2可以通过1to3,3to2松弛,如果k在内层的话,dis[1][2]不能通过dis[1][3]和dis[3][2]松弛,因为此时dis[1][3],dis[3][2]还没更新,如上图,因为for循环具有顺序性
        for (int i=1; i<=n; i++) {
            for (int j=1; j<=n; j++) {
                if (dis[i][j]>dis[i][k]+dis[k][j]) {
                    dis[i][j]=dis[i][k]+dis[k][j];
                }
            }
        }
    }


dis[i][j]表示从i点到j点的最短距离,很多关于floyd算法的文章里面都通过动态规划的思想去理解该算法,我个人认为floyd算法的正确性是基于:要求一个图中任意两个点的最短路径,首先要检测最短路径所经过的点(最坏情况1-n最短路径经过所有的点1-2-3-4-...-n),floyd算法最外层循环做的就是这件事,如果i,j固定的话,k是枚举所有的点,寻找哪些点能对最短路径进行松弛,最坏的情况下(e.g,from (1 to n) (2,3,.....n-1)都能对其进行松弛操作),只要枚举了所有的情况(一共n^3种),都能实现floyd算法.所以我觉得floyd算法并不是基于动态规划思想的.因为前一步对于下一步并没有实质的影响,只需要枚举所有的情况就行了,想表达的意思是最外层循环可以无序(如何判断i to j不需要更新?给自己留个坑,想想如何优化)

注意floyd算法并不能解决带有负权回路的图,因为如果存在负权回路,最短路径可以一直减小,减小,to -inf

2.Dijkstra算法(单源最短路径,不能解决负权边)

代码就不贴了...

Dijkstra算法的基本步骤是:

1.首先寻找一个点s作为源点.记录每个点到源点距离为dis[i],初始情况dis[s]=0,其他dis[i]=inf

2.将所有顶点分为两部分,一部分是已知最短路径的顶点集合P,另一部分是未知最短路径的集合Q(最开始只有源点在最短路径集合P),然后寻找Q中离源点最近的点,如果这个点离源点最近,意味着源点到这个点的路径从今以后都不需要松弛(因为它已经是最短的了),所以我们每次都通过这个点的所有出边对其他点进行松弛,松弛成功的话(a>b+c),更新dis数组,并把该点加入到集合P中.

3.重复2直到集合Q为空

Floyd和Dijkstra的比较:

Floyd算法时间复杂度为n^3,它可以用来求任意两点之间的最短距离,而Dijkstra算法是用来求一个点到其他任意点的最短距离,时间复杂度为(M+N)logN,如果直接通过一个for循环枚举所有的点求任意两点最短距离Dijkstra算法可以在时间复杂度为N*(M+N)logN内实现,可以看出Dijkstra所用时间更少(但在最坏情况下,M=N^2,并不成立.仅在稀疏图中成立),

(留个问题给自己思考,如何通过Dijkstra算法优化求任意两个点的最短距离)

3.Bellman-Ford算法(求源点到任意点最短距离(可以解决负权边))

核心代码:

for (int k=1; k<=n-1; k++) {
        for (int i=1; i<=m; i++) {
            if (dis[v[i]]>dis[u[i]]+w[i]) {
                dis[v[i]]=dis[u[i]]+w[i];
            }
        }
    }

dis数组和dijkstra中的dis数组一样.

Bellman-Ford算法的思路可以通过代码看出来,枚举所有边对原点进行松弛,外层循环一共枚举了n-1次,其实自己画图可以明白,for(int i)整个循环结束后,源点到它所有的出边的值已经更新到正确结果了,因为直接相连的就是最短路,然后继续执行扩展,整个图就都被扩展到了,就得到了最后结果.


最坏情况就是上图需要执行n-1外层循环,4个点从左往右依次扩展,第一次内层循环执行完毕,2被扩展,第二次3被扩展,第三次4被扩展,结束循环,一共3=4-1次扩展

上面情况限于每个点出度为1的情况,如果出度大于1的话我觉得肯定是不需要n-1次就能扩展完毕的.

Bellman-Ford与Dijkstra算法的比较:

Dijkstra算法不能解决含有负权边的图,因为如果含有负权边dis数组每次寻找最短的都会破坏P数组的不变性质,Bellman-Ford算法因为每次都是松弛所有边,持续n-1次,依然能处理负权边的问题

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值