[アルゴリズム]ダイクストラ法(最短経路アルゴリズムで重み付けされた有向グラフ)

まず、重み付き有向グラフ

 

第二に、アルゴリズムの原理

1)我々はリストを作成または配列の長さがあるので、我々は、1-6のノードからのものであるため、N + 1、インデックス= 0は、1~6の範囲(計算の都合)におけるサイクルの使用済み部分はありません。

2)ループの前に、我々は配列を初期化し、DIS配列をマーク:

  DISアレイ記憶開始点(開始)我々の要求、すべてのポイントの残りの部分への最短経路。初期化時間は、距離のみが(すなわちsys.maxsize)MAX_INTに初期化されていない、直接に、ノードに直接自分自身を遠ざけるように初期化。

  それは状態が真であると計算された場合、ノードステータスマーク保存、それはまだ計算し、Falseをされていません

3)なお、我々のみサイクル[1、n]の範囲、サイクルを開始します。インデックス== 0がサイクルに含まれていません。

4)N == 1、Falseに要素をマークするために対応する要素をディスすべての要素を見つけます。最小値は10である見つける、対応するインデックスは3、すなわち、ノード3です。次いで3に直接ノード(マークに対応し、また、偽の場合)ことが見出さ重みアレイは、ノード4にここで3直接見つけることができ、重量は50です。この場合、DISを分析[3] +50 <DIS [4]、確立された場合に、使用されるDIS [3] +50更新DIS [4]。DIS [4]のでMAX_INTに等しいので、DIS [4]は60に更新されます。

5)N == 2、DISが要素がFalseにマーク要素に対応するすべての要素を見つけます。最小値は、対応するノード5〜30である見つけます。次いで、重量アレイ、直接5検索ノード(マークに対応し、また、偽の場合)、番号である。ノード4及び6、及び重量が20と60です。DIS [4]が50に更新されるように、確立その結果、DIS [5] +20 <DIS [4]このケースを分析します。同様DISは、[6]は90に更新されます。

6)N == 3、Falseに要素をマークするために対応する要素をディスすべての要素を見つけます。最小値は、対応ノード4〜50である検索。次いで、重量アレイ、4は、直接(マークに対応し、また、偽の場合)ノードを見つけるために、ノード6、および重量が10です。DIS [6]が60に更新されるように、確立その結果、DIS [4] +10 <DIS [6]この場合の分析。

7)N==4时,找到所有Dis元素中,对应mark元素为False的元素。找出其中最小值为60,对应节点6。然后在weight数组中,找到6能直接到的节点(且对应mark也要为False),结果找不到6能直接到的节点。

8)N==5时,找到所有Dis元素中,对应mark元素为False的元素。找出其中最小值为max_int,对应节点2。然后在weight数组中,找到2能直接到的节点(且对应mark也要为False),为3号节点,且权重为5。此时判断dis[4]+10<dis[6],结果不成立,不成立则不更新dis[3]。

9)N==6时,已经找到到对应mark为False的元素,直接break出循环。整个计算最短路径的过程结束。

10)可以看到N==6时得到Dis数组的结果是:[max_int,0,max_int,10,50,30,60]。除去index==0的元素,从1-6的元素,即是节点1到所有元素对应的距离(1到2的距离为max_int,说明没有路线)。

三、Python实现

import numpy as np
import sys


def dijkstra(start, graph_struct, node):
    """
    function:dijkstra
    args:
        start 要计算的起始点
        graph_struct 带权有向图的结构
        node 图中节点个数
    return:
        dis 元素为-1时,表示没有路径。其余为距离
    """
    # n表示有N个点,m表示M条边,x表示求那个点到所有点的最短路径
    n, m, x = node, len(graph_struct), start
    max_int = sys.maxsize
    weight = np.full([n + 1, n + 1], -1)
    dis = np.full(n + 1, max_int)
    # 初始化权重数组,自己到自己为0.其他为暂为-1
    for i in range(1, n + 1):
        weight[i][i] = 0

    for i in graph_struct:
        # 所有存在边的位置填上权重,没有关系的位置保持为-1,表示不可直接到达
        weight[i[0]][i[1]] = i[2]
        # 如果是与我们要求的x点相关的点,则也将x到i的权重填入dis列表中
        if i[0] == x:
            dis[i[1]] = i[2]

    # 程序走到这里,我们就有了权重数组 以及 dis数组(x到各个点的距离,如果没有边,则为max_int)
    # dis : [max_int,  0,  max_int,  10,  max_int,  30,  100], dis[0]不纳入计算,为了方便,我们只考虑index>=1的部分

    # 定义内部search函数,开始计算x到所有点的最短路径,最终更新到dis中
    def search(x, dis, weight, n):
        """
        function:search
        args:
            x 要求的点
            dis 距离数组
            weight 权重数组
            n 节点的个数
        return:dis
        """
        mark = np.full(n + 1, False)  # 创建一个mark数组,元素个数为n+1,[1,n]表示1-n点是否被当成最小值加过,已经加过为True,未被加过为False
        mark[x] = True  # 要求的点x,直接标记为加过
        dis[x] = 0  # 自己到自己的距离为0
        count = 1  # 当前已经加了几个点,当前只有x点,所以初始化为1

        # 开始循环,当count<=n时,说明还有点未被加过
        while count <= n:
            locate = 0  # locate记录计算出来马上要被加的点
            min = max_int  # 用于求最小值时比较用
            # 找到dis里面,还没有加过的位置(mark[idx]=False)里面数的最小值对应的index。
            # dis : [9223372036854775807 0 9223372036854775807 10 9223372036854775807 30 100]
            # mark : [False,True,False,False,False,False],从中找出10的index为 3
            # 该for循环完毕后,min中的值就是最小值10
            for i in range(1, n + 1):
                if not mark[i] and dis[i] < min:
                    min = dis[i]
                    locate = i
            # 如果locate为0,则说明所有点都被加完了,直接退出循环
            if locate == 0: break
            # 如果locate不为0,说明找到了需要加的点,先对其进行标记
            mark[locate] = True
            # 加一个点count增1
            count += 1

            # 从我们找到的需要加的点locate(例如3)开始,看weight数组中他到各个点的距离
            for i in range(1, n + 1):
                # 如果某个点已经被加过了,我们就不计算locate到这个点的距离了
                # 如果locate到某个点的距离为-1,说明没有路,也不计算
                # 条件3:x到locate的距离(dis[locate]) + locate到点i的距离(weight[locate][i]) < x到i的距离 才能更新
                if not mark[i] and weight[locate][i] != -1 and (
                        dis[locate] + weight[locate][i] < dis[i]):
                    # 条件都满足,则计算,并更新dis中x-->i的距离
                    dis[i] = dis[locate] + weight[locate][i]

        return dis

    # 调用search开始计算x到各个点的距离,记录到dis数组中
    dis = search(x, dis, weight, n)

    # 打印dis数组
    for i in range(1, len(dis)):
        if dis[i] == max_int:
            dis[i] = -1
        print("%s点到%s点 %s" % (x, i, "的最短路径为%s" % dis[i] if dis[i] != max_int else '没有路'))

    # 返回
    return dis


if __name__ == '__main__':
    # 列举所有的边的权重,并写入weight列表
    weight_init = [(1, 3, 10), (1, 5, 30), (1, 6, 100), (2, 3, 5), (3, 4, 50), (4, 6, 10), (5, 6, 60), (5, 4, 20)]
    dis = dijkstra(1, weight_init, 6)

 

### Dijkstra算法原理还是比较简单的,但是使用代码实现的时候比较绕。需要多加复习,熟记于心。

 

おすすめ

転載: www.cnblogs.com/leokale-zz/p/12378193.html