最短路径——Dijkstra与Floyd

最短路径:对于网图来说,是指两顶点之间经过的边上权值之和最少的路径,并且我们称路径上的第一个顶点是源点,最后一个顶点是终点。

迪杰斯特拉 ( D i j k s t r a ) (Dijkstra) (Dijkstra)

迪杰斯特拉 ( D i j k s t r a ) (Dijkstra) (Dijkstra):是一个按路径长度递增的次序产生最短路径的算法。

原理:假设 S S S为已求得的从源点出发的最短路径长度的顶点的集合,则可证明:下一条次最短路径(设其终点为 x x x)要么是弧 ( v , x ) (v,x) (v,x),要么是从源点出发的中间只经过 S S S中的顶点而最后到达顶点x的路径。

算法实现
 1.先设一个辅助列表 D i s Dis Dis用来记录自源点 v 0 v_0 v0到各个顶点的最短路径长度,设 D i s Dis Dis的初始值为 D i s [ i ] = l e n ( v 0 , v i ) Dis[i]=len(v_0,v_i) Dis[i]=len(v0,vi)
 2.分别设 S S S为已找到最短路径的顶点集合, U U U为未找到最短路径的顶点集合。对 D i s [ i ] ( v i ∈ U ) Dis[i](v_i\in U) Dis[i](viU)的值进行替换: D i s [ i ] = m i n { D i s [ j ] + l e n ( v j , v i ) , D i s [ i ] } , ( v j ∈ S , v i ∈ U ) \\Dis[i]=min\{Dis[j]+len(v_j,v_i),Dis[i]\},(v_j\in S,v_i\in U) Dis[i]=min{Dis[j]+len(vj,vi),Dis[i]},(vjS,viU)
i 0 , s . t . D i s [ i 0 ] = m i n { D i s [ i ] } ( v i ∈ U ) i_0,s.t.Dis[i_0]=min\{Dis[i]\}(v_i\in U) i0,s.t.Dis[i0]=min{Dis[i]}(viU),则我们便找到了由 v 0 v_0 v0 v i 0 v_{i_0} vi0的最短的路径长度,此时将 v i 0 v_{i_0} vi0添加进 S S S v i 0 v_{i_0} vi0 U U U中删除即可。
 3.反复进行上述操作,直至 U U U为空。
Note:上述做法只能求得最短路径的长度这一数值,但是无法得知具体行进路径,若想要得到具体路径,可增加一个变量 T r a c e Trace Trace来记录行进过程。

代码以及测试数据

# -*- coding: utf-8 -*-
"""
Created on Sat Mar 30 09:53:07 2019

@author: Administrator
"""

from numpy import *

def Dijkstra(Mat,v):
    #邻接矩阵matrix,起点v
    #默认图连通
    L=len(Mat)                  #顶点个数

    Dis=list(Mat[v])            #表示起点到其余顶点的距离

    Min=v                       #表示从那些未访问的顶点中所找到的最短路径所对应的顶点标号
    S=[]                        #已访问的顶点集合
    U=list(range(L))            #未访问的顶点集合
    S.append(v)                 #先访问起点
    U.remove(v)
    Trace=[[None]]*L             #储存具体路径
    
    for x in range(L):          #初始化路径长度列表
        if Mat[v][x]!=inf:Trace[x]=[v,x]
    Trace[v]=[v]

    while(len(U)>0):            #若还存在未访问的顶点,则继续循环
        D=[]
        for x in U:
        #重新设置Dis
            if Dis[Min]+Mat[Min][x]<Dis[x]:
                Dis[x]=Mat[x][Min]+Dis[Min]
                Trace[x]=Trace[Min]+[x]
            D.append([x,Dis[x]])
        #寻找次短路径    
        Min=sorted(D, key=lambda x:x[1])[0][0]
        S.append(Min)
        U.remove(Min)
    
    return Dis,Trace
            
Mat=array([[ 0,10,inf,inf,inf,11,inf,inf,inf]
,[10,0,18,inf,inf,inf,16,inf,12]
,[inf,18,0,22,inf,inf,inf,inf,8]
,[inf,inf,22,0,inf,inf,24,16,21]
,[inf,inf,inf,inf,0,26,inf,7,inf]
,[11,inf,inf,inf,26,0,17,inf,inf]
,[inf,16,inf,24,inf,17,0,19,inf]
,[inf,inf,inf,16,7,inf,19,0,inf]
,[inf,12,8,21,inf,inf,inf,inf,0]])

Dis,Trace=Dijkstra(Mat,0)


弗洛伊德 ( F l o y d ) (Floyd) (Floyd)

弗洛伊德 ( F l o y d ) (Floyd) (Floyd)算法是通过在邻接矩阵中不断地尝试比较在两个顶点间的各条路径来得到最短路径的,即尝试不断地加入中转的顶点。

算法实现
 1.从图的带权邻接矩阵 A = ( a i , j ) n × n , ( i , j = 1 , 2 , . . . , n − 1 ) A=(a_{i,j})_{n×n},(i,j=1,2,...,n-1) A=(ai,j)n×n,(i,j=1,2,...,n1)开始,递归地进行 n n n次更新,即由矩阵 D ( 0 ) = A D(0)=A D(0)=A,按一个公式,构造出矩阵 D ( 1 ) D(1) D(1);又用同样地公式由 D ( 1 ) D(1) D(1)构造出 D ( 2 ) D(2) D(2);…;最后又用同样的公式由 D ( n − 1 ) D(n-1) D(n1)构造出矩阵 D ( n ) D(n) D(n)。矩阵 D ( n ) D(n) D(n) i i i j j j列元素便是 v i v_i vi v j v_j vj的最短路径长度,称 D ( n ) D(n) D(n)为图的距离矩阵。
 2.假设已经有了 D [ m ] D[m] D[m],下面阐述构造 D [ m + 1 ] D[m+1] D[m+1],对于 D [ m ] D[m] D[m]的的元素 a i , j a_{i,j} ai,j,将 D [ m + 1 ] D[m+1] D[m+1]的元素 b i , j b_{i,j} bi,j更新为 b i , j = m i n { a i , k + a k , j } ( k = 0 , 1 , 2 , . . . , n − 1 ) b_{i,j}=min\{a_{i,k}+a_{k,j}\}(k=0,1,2,...,n-1) bi,j=min{ai,k+ak,j}(k=0,1,2,...,n1),对每个 a i , j a_{i,j} ai,j进行同样的更新,便可得到 D [ m + 1 ] D[m+1] D[m+1]
 3.直到更新至 D [ n ] D[n] D[n]
Note:同样,上述方法无法得到具体路径,因此额外设一个变量 P [ 0 ] P[0] P[0],在计算 D [ m ] D[m] D[m]时同时计算 P [ m ] P[m] P[m],需要注意的是初始的 P [ 0 ] P[0] P[0]的设定:
P [ 0 ] = [ [ i   f o r   i   i n   r a n g e ( L ) ]   f o r   j   i n   r a n g e ( L ) ] P[0]=[[i\ for\ i\ in\ range(L)]\ for\ j\ in\ range(L)] P[0]=[[i for i in range(L)] for j in range(L)],即初始的 P P P中元素表示 v i v_i vi走向 v j v_j vj时,路径的终点为 v j v_j vj。还需要注意的时如何通过最终得到的 P P P是读取具体路径的:若 P = ( p i , j ) n × n , ( i , j = 1 , 2 , . . . , n − 1 ) P=(p_{i,j})_{n×n},(i,j=1,2,...,n-1) P=(pi,j)n×n,(i,j=1,2,...,n1),则 p i , j = i   o r   j p_{i,j}=i\ or\ j pi,j=i or j表示由 v i v_i vi直接通过弧 ( v i , v j ) (v_i,v_j) (vi,vj)走向 v j v_j vj,若 p i , j = k   a n d   k ! = i   o r   j p_{i,j}=k\ and\ k!=i\ or\ j pi,j=k and k!=i or j,则表示 v i v_i vi号顶点走向 v j v_j vj号顶点的最短路径中存在中转点 v k v_k vk,接着再考察 p i , k p_{i,k} pi,k p k , j p_{k,j} pk,j,一直进行下去。

代码以及测试数据

# -*- coding: utf-8 -*-
"""
Created on Sat Mar 30 20:13:26 2019

@author: Administrator
"""
from numpy import *
def Floyd(Mat):
    L=len(Mat)
    D=array(Mat)
    P=[[i for i in range(L)] for j in range(L)]
#    print(P)
    for k in range(L):
        for i in range(L):
            for j in range(L):
                if D[i][j]>D[i][k]+D[k][j]:
                    D[i][j]=D[i][k]+D[k][j]
                    P[i][j]=k
#                    print(i,j,k)
#                    print(P)
    return D,P

Mat=array([[ 0,10,inf,inf,inf,11,inf,inf,inf]
,[10,0,18,inf,inf,inf,16,inf,12]
,[inf,18,0,22,inf,inf,inf,inf,8]
,[inf,inf,22,0,inf,inf,24,16,21]
,[inf,inf,inf,inf,0,26,inf,7,inf]
,[11,inf,inf,inf,26,0,17,inf,inf]
,[inf,16,inf,24,inf,17,0,19,inf]
,[inf,inf,inf,16,7,inf,19,0,inf]
,[inf,12,8,21,inf,inf,inf,inf,0]])
    
D,P=Floyd(Mat)

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值