• [总结]最短路径算法


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

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

    Dijkstra(迪杰斯特拉)算法

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

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

    因此,Dijkstra算法描述如下:
    假设存在(G=<V,E>),源顶点为(V_0)(S={V_0}),(distance[i])记录(V_0)(i)的最短距离,(matrix[i][j])记录从(i)(j)的边的权值,即两点之间的距离。
    1)从(V-S)中选择使(dist[i])值最小的顶点(i),将(i)加入到(U)中;
    2)更新与(i)直接相邻顶点的dist值。(dist[j]=min{dist[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)),这样一来,当我们遍历完所有节点(k)(arcs(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算法

  • 相关阅读:
    重拾数学--初中--有理数
    Python中的运算符
    PyQt5实现虚拟摇杆
    Python无重复字符的最长子串
    Python两数相加
    Python两数之和
    DBMS,B树和B+树
    浮点数表示
    Lamada表达式
    Java编程思想P159页的错误
  • 原文地址:https://www.cnblogs.com/hellojamest/p/12234648.html
Copyright © 2020-2023  润新知