[总结]最短路径算法

所谓最短路径问题是指:如果从图中某一顶点(源点)到达另一顶点(终点)的路径可能不止一条,如何找到一条路径使得沿此路径上各边的权值总和(称为路径长度)达到最小。

下面我们介绍两种比较常用的求最短路径算法:

Dijkstra(迪杰斯特拉)算法

迪杰斯特拉算法思想是按路径长度递增的次序一步一步并入来求取,是贪心算法的一个应用,用来解决单源点到其余顶点的最短路径问题。另外,要注意D算法是无法解决负权重问题的,所以图的权重必须为正。
首先,我们引入一个辅助向量D,它的每个分量D[i]表示当前找到的从起始节点v到终点节点vi的最短路径的长度。它的初始态为:若从节点v到节点vi有弧,则D[i]为弧上的权值,否则D[i],显然,长度为D[j]=MinD[i]|viV的路径就是从v出发最短的一条路径,路径为(v,vi)
那么,下一条长度次短的最短路径是哪一条呢?假设次短路径的终点是vk,则可想而知,这条路径或者是(v,vk)或者是(v,vj,vk)。它的长度或者是从vvk的弧上的权值,或者是D[j]与从vjvk的权值之和。

一般情况下,假设S为已知求得的最短路径的终点集合,则可证明:一条最短路径(设其终点为x)或者是弧(v,x)或者是中间只经过S中的顶点而最后到达顶点x的路径。这可用反证法来证明,假设此路径上有一个顶点不在S中,则说明存在一条终点不在S中而长度比此路径短的路径。但是这是不可能的。因为,我们是按路径长度的递增次序来产生个最短路径的,故长度比此路径短的所有路径均已产生,他们的终点必定在S集合中,即假设不成立。

因此,Dijkstra算法描述如下:
假设存在G=<V,E>,源顶点为V0S=V0,distance[i]记录V0i的最短距离,matrix[i][j]记录从ij的边的权值,即两点之间的距离。
1)从VS中选择使dist[i]值最小的顶点i,将i加入到U中;
2)更新与i直接相邻顶点的dist值。dist[j]=mindist[j],dist[i]+matrix[i][j]
3)直到S=V,所有顶点都包含进来了,算法停止。

图使用邻接矩阵存储,python代码如下:

# _*_ encoding:utf-8 _*_
# 辅助信息
# 图中的顶点数
V = 7
# 标记数组:used[v]值为False说明改顶点还没有访问过,在S中,否则在U中!
used = [False for _ in range(V)]
# 距离数组:distance[i]表示从源点s到i的最短距离,distance[s]=0
distance = [float('inf') for _ in range(V)]
# cost[u][v]表示边e=(u,v)的权值,不存在时设为INF
cost = [[float('inf') for _ in range(V)] for _ in range(V)]


def dijkstra(s):
    distance[s] = 0
    while True:
        # v在这里相当于是一个哨兵,对包含起点s做统一处理!
        v = -1
        # 从未使用过的顶点中选择一个距离最小的顶点
        for u in range(V):
            if not used[u] and (v == -1 or distance[u] < distance[v]):
                v = u
        if v == -1:
            # 说明所有顶点都维护到S中了!
            break

        # 将选定的顶点加入到S中, 同时进行距离更新
        used[v] = True
        # 更新U中各个顶点到起点s的距离。之所以更新U中顶点的距离,是由于上一步中确定了k是求出最短路径的顶点,从而可以利用k来更新其它顶点的距离;例如,(s,v)的距离可能大于(s,k)+(k,v)的距离。
        for u in range(V):
            distance[u] = min(distance[u], distance[v] + cost[v][u])


if __name__ == '__main__':
    for _ in range(12):
        v, u, w = list(map(int, input().split()))
        cost[v][u] = w
    s = int(input('请输入一个起始点:'))
    dijkstra(s)
    print(distance)

Floyd(弗洛伊德)算法

Floyd算法是一个经典的动态规划算法。是解决任意两点间的最短路径(称为多源最短路径问题)的一种算法,可以正确处理有向图或无向图或负权(但不可存在负权回路)的最短路径问题,同时也被用于计算有向图的传递闭包。
从任意节点i到任意节点j的最短路径不外乎2种可能:1)直接从节点i到节点j,2)从节点i经过若干个节点k到节点j。所以,我们假设arcs(i,j)为节点i到节点j的最短路径的距离,对于每一个节点k,我们检查arcs(i,k)+arcs(k,j)<arcs(i,j)是否成立,如果成立,证明从节点i到节点k再到节点j的路径比节点i直接到节点j的路径短,我们便设置arcs(i,j)=arcs(i,k)+arcs(k,j),这样一来,当我们遍历完所有节点karcs(i,j)中记录的便是节点i到节点j的最短路径的距离。

图使用邻接矩阵存储,python代码如下:

# _*_ encoding:utf-8 _*_
# 辅助信息
# 图中的顶点数
n = 4
# 距离数组:distance[i]表示从源点s到i的最短距离,distance[s]=0
matrix = [[float('inf') for j in range(n)] for i in range(n)]

def floyd(matrix,n):
    for i in range(n):
        for j in range(n):
            for k in range(n):
                matrix[j][k] = min(matrix[j][k], matrix[j][i] + matrix[i][k])
    return matrix


if __name__ == '__main__':
    matrix[0][1] = 3
    matrix[1][2] = 1
    matrix[2][3] = 1
    matrix[1][3] = 4
    for i in range(n):
        matrix[i][i] = 0
    res = floyd(matrix,n)
    print(res)

参考:
Python实现迪杰斯特拉算法
最短路径问题:Dijkstra与Floyd算法

posted @   Jamest  阅读(1072)  评论(0编辑  收藏  举报
编辑推荐:
· 记一次.NET内存居高不下排查解决与启示
· 探究高空视频全景AR技术的实现原理
· 理解Rust引用及其生命周期标识(上)
· 浏览器原生「磁吸」效果!Anchor Positioning 锚点定位神器解析
· 没有源码,如何修改代码逻辑?
阅读排行:
· 全程不用写代码,我用AI程序员写了一个飞机大战
· DeepSeek 开源周回顾「GitHub 热点速览」
· 记一次.NET内存居高不下排查解决与启示
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· .NET10 - 预览版1新功能体验(一)
点击右上角即可分享
微信分享提示