Dijstral算法:形成过程、原理、算法解析、过程图解

#Dijstral算法找到了确定的开始顶点到其他任意顶点的最短路问题
#Dijstral算法的思路:以一个点A为出发点,求这个点到点C的最短路径。可以这样求,已知A到B的最短路径,B与C又是直接连通的,A到C也是直接连通的,所以就是两条路径比较,
#从A直接到C这条路和从A到B的最短路+从B直接到C
#将这个例子倒推,把B变成多个点,那么就是在众多子点中找路径最短的做为中转点
#具体的实现思路如下:找到最短的路作为中转点,看从开始点直接到其他点还是经过中转点到其他点距离近,选短的那条路径,并把这条路径连上的点作为新的中转点,重复此操作
#注意:每一次确定作为中转点之后这个点就不能再次作为中转点
#具体这样做的原理大家可以见运筹学里面的求最短路问题,有一个反证法。

具体代码及注释如下:

#Dijstral算法找到了确定的开始顶点到其他任意顶点的最短路问题
#Dijstral算法的思路:以一个点A为出发点,求这个点到点C的最短路径。可以这样求,已知A到B的最短路径,B与C又是直接连通的,A到C也是直接连通的,所以就是两条路径比较,
#从A直接到C这条路和从A到B的最短路+从B直接到C
#将这个例子倒推,把B变成多个点,那么就是在众多子点中找路径最短的做为中转点
#具体的实现思路如下:找到最短的路作为中转点,看从开始点直接到其他点还是经过中转点到其他点距离近,选短的那条路径,并把这条路径连上的点作为新的中转点,重复此操作
#注意:每一次确定作为中转点之后这个点就不能再次作为中转点
#具体这样做的原理大家可以见运筹学里面的求最短路问题,有一个反证法。
def Dijkstral(g,v):
    dist=[-1]*MAXV#dist列表代表distance,表示从开始顶点到这个点的最短路劲长度(权值),在之后,会挑选值最小的带你作为中转点
    path=[-1]*MAXV#表示从开始结点到这个点的最短路径中到达这个点的前一个点是哪个点
    S=[0]*MAXV#S是解释当中的vset列表,用于表示这个点是否曾作为中转点,是就标记1,不是就标记0,做过中转的点不再作为中转点

    for i in range(g.n):#对dist列表和path列表进行初始化
        dist[i]=g.edges[v][i]#因为一开始只能从开始结点v走,没有设置中转结点,所以dist里放的就是从开始结点到这个点的直接路径,也就是边长的值
        if g.edges[v][i]<INF:
            path[i]=v
        else:#如果走不通,前一个结点的值就置为-1
            path[i]=-1

    S[v]=1#开始点不能作为中转点,所以将它在S中的值置为-1
    u=-1#u用于指向指向中转顶点,一开始初始化的时候没有中转顶点,所以设置为-1

    for i in range(g.n-1):
        mindis=INF
        for j in range(g.n-1):
            mindis=INF

            #这个块是对初始化条件进行操作,确立了中转顶点是谁
            for j in range(g.n):#找到现在初始化没有中转顶点时dist的最小值,仍然是使用不断更新的方法
                if S[j]==0 and dist[j]<mindis:
                    u=j#标记为中转顶点
                    mindis=dist[j]
            S[u]=1#将这个中转顶点标记为已操作

            #用刚刚确立的中转顶点更新从开始顶点到其他点的最短路径的值
            for j in range(g.n):
                if S[j]==0:
                    if g.edges[u][j]<INF and dist[u]+g.edges[u][j]<dist[j]:#从中转顶点到其他顶点有边并且借助中转顶点走的路程(开始顶点到中转顶点的值+中转顶点直接到该点的边长)要比直接到要短
                        dist[j]=dist[u]+g.edges[u][j]#更新dist
                        path[j]=u#标记这个到达最短路径的前一个结点
            #然后再进行最外层的for循环
        DispAllPath(dist,path,S,v,g.n)


def DispAllPath(dist,path,S,v,n):#输出最短路径,其中dist、path、S是最后形成的列表,v是开始顶点,n是顶点个数
    #因为到某个顶点最终只能是找到最短路径中到这一个点的前一个顶点path,所以从后往前找
    for i in range(n):
        if S[i]==1 and i!=v:
            apath=[]#建立apath用于存储经过的顶点

            #输出基本信息
            print("从%d到%d最短路径长度:%d \t路径:"%(v,i,dist[i]),end='')
            apath.append(i)#加上最后一个点的序号
            k=path[i]#k是到达i顶点的前一个顶点序号

            if k==-1:#没有前一个顶点
                print('无路径')
            else:#有前一个顶点
                while k!=v:#还没到起点
                    apath.append(k)#添加前一个顶点
                    k=path[k]#更新k,再作为前一个顶点
                #再次进入while循环
                apath.append(v)#最后再加上起点这个顶点
                apath.reverse()#把列表倒序
                print(apath)

 

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

踏歌~

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值