基礎算法-dijkstra最短路算法

最短路算法dijkstra的運用

尋找到達城市的最短路徑



如圖

avater


1、一般用鄰接矩陣表示一個圖

鄰接矩陣:

A = [
	if exist(A(i,j)):
		return 1
	else:
		return 0
]

則一個圖的表示方法:

INF = 999
graph = [
    [0, INF, INF, INF, INF, INF, INF, INF, INF, INF],
    [4, 0, INF, INF, INF, INF, INF, INF, INF, INF],
    [6, INF, 0, INF, INF, INF, INF, INF, INF],
    [INF, 5, INF, 0, INF, INF, INF, INF, INF],
    [INF, 7, 3, 3, 0, INF, INF, INF, INF, INF, INF],
    [INF, INF, 13, INF, INF, 0, INF, INF, INF, INF],
    [INF, INF, INF, 3, 2, INF, 0, INF, INF, INF],
    [INF, INF, INF, INF, 9, 1, INF, 0, INF, INF],
    [INF, INF, INF, INF, INF, 5, 3, 4, 0, INF]
 ]

2、爲了好看我們用地圖字典表示圖

graph = {
        "北京": {"天津": 4, "蘇州": 6, "北京": 0},
        "天津": {"上海": 5, "杭州": 7, "天津": 0},
        "蘇州": {"杭州": 3, "鄭州": 13, "蘇州": 0},
        "上海": {"杭州": 3, "福州": 3, "上海": 0},
        "杭州": {"福州": 2, "合肥": 9, "杭州": 0},
        "鄭州": {"合肥": 1, "廣州": 5, "鄭州": 0},
        "福州": {"廣州": 3, "福州": 0},
        "合肥": {"廣州": 4, "合肥": 0},
        "廣州": {"廣州": 0}
    }

3、dijkstra算法以及實現

(1)輸入:

  • 1)圖graph
  • 2)源點v0

(2)算法原理

1)一開始 S裏面只有源點 v0

2)離 v0最近的那個點爲 u,把 u放進 S,並且記錄這一次,到達 u的點和最短路

3)查看當前能夠到達的點,列出所有能夠到達的點它到源點的距離,排序後,最短的那個是新的 u

4)重複1-3,直到 S包含所有 graph的點

(3)定義變量:

1)有一個集合S,存放已經走過的點

2)有一個節點u,代表下一個要放進S的點

3)有一個數據結構dist{[shortest_path],<shortest_path_value>},用來存放最短路徑和最短路的值

4)有一個shortest_path{},以 <key,value> 的形式存放,最短路徑中,到達節點 key的上一個節點作爲 value 的值。

(4)代碼

#!/usr/bin/env python
# -*- coding: utf-8 -*-


INF = 999


class Dijkstra(object):
    """
    用dijkstra求最短路,輸入參數爲一個圖和源點,graph實際是上一個二維數組,source表示的是二維數組中的第行個元素是源
    時間複雜度O(n^2)
    """
    def __init__(self, graph, source):
        self.graph = graph
        self.dist = {}
        self.short_path = {}
        self.s_collect = set()

        self.source = source

    def get_shortest_path_src_to_dest(self, des):
        """
        獲取到達某目的地點的最短路信息
        :param dis: 目的地點
        :return:
        """
        distance = self.get_shortest_path()
        return distance[des]

    def get_shortest_path(self):
        """
        獲取全圖的所有最短路徑信息
        :return:
        """
        self._exec_shortest_path_calculation()
        for key in self.dist.keys():
            k = key
            while k != self.source:  # 獲取路徑
                self.dist[key][0].insert(0, self.short_path[k])
                k = self.short_path[k]
        return self.dist

    def _exec_shortest_path_calculation(self):
        """
        計算最短路,得到圖中最短路的信息
        :return:
        """
        now_node = self.source
        self.dist = dict((k, [[], INF]) for k in self.graph.keys())  # 假設初始化點到原點都是無限大
        self.dist[now_node][1] = 0  # 源點到源點的距離爲0

        while len(self.s_collect) < len(self.graph):
            self.s_collect.add(now_node)

            for next in self.graph[now_node]:
                if self.dist[now_node][1] + self.graph[now_node][next] < self.dist[next][1]:
                    self.short_path[next] = now_node  # next的點來自哪個節點
                    self.dist[next][1] = self.dist[now_node][1] + self.graph[now_node][next]

            new_short = INF  # 從剩下的未確定點中選擇最小距離點作爲新的擴散點
            for now in self.dist.keys():
                if now in self.s_collect:
                    continue
                if self.dist[now][1] < new_short:
                    new_short = self.dist[now][1]
                    now_node = now


def print_path(source, short_path):
    for key, path in short_path.items():
        if key == source:
            continue
        path[0].append(key)
        print("%s 到 %s 最短路徑爲:%s, 路徑: %s"
              % (source, key, path[1], "->".join(path[0])))


def main():
    source = "北京"
    graph = {
        "北京": {"天津": 4, "蘇州": 6, "北京": 0},
        "天津": {"上海": 5, "杭州": 7, "天津": 0},
        "蘇州": {"杭州": 3, "鄭州": 13, "蘇州": 0},
        "上海": {"杭州": 3, "福州": 3, "上海": 0},
        "杭州": {"福州": 2, "合肥": 9, "杭州": 0},
        "鄭州": {"合肥": 1, "廣州": 5, "鄭州": 0},
        "福州": {"廣州": 3, "福州": 0},
        "合肥": {"廣州": 4, "合肥": 0},
        "廣州": {"廣州": 0}
    }

    dj = Dijkstra(graph, source)
    print_path(source, dj.get_shortest_path())


if __name__ == '__main__':
    main()

運行結果:
avater

4、鄰接矩陣和圖的字典表示法互換方法:

#!/usr/bin/env python
# -*- coding: utf-8 -*-


# adjacency martix
INF = 999
graph_mapper = {
    0: "北京",
    1: "天津",
    2: "蘇州",
    3: "上海",
    4: "杭州",
    5: "鄭州",
    6: "福州",
    7: "合肥",
    8: "廣州"
}

graph = [
    [0, 4, 6, INF, INF, INF, INF, INF, INF, ],
    [INF, 0, INF, 5, 7, INF, INF, INF, INF, ],
    [INF, INF, 0, INF, 3, 13, INF, INF, INF, ],
    [INF, INF, INF, 0, 3, INF, 3, INF, INF, ],
    [INF, INF, INF, INF, 0, INF, 2, 9, INF, ],
    [INF, INF, INF, INF, INF, 0, INF, 1, 5, ],
    [INF, INF, INF, INF, INF, INF, 0, INF, 3, ],
    [INF, INF, INF, INF, INF, INF, INF, 0, 4, ],
    [INF, INF, INF, INF, INF, INF, INF, INF, 0, ]
]


def adjacency_to_dictmap(graph_adjacency, graph_mapper):
    """
    鄰接矩陣轉字典圖
    :param graph_adjacency:
    :return:
    """
    graph_dict = {}
    for i in range(len(graph_adjacency)):
        graph_dict[graph_mapper[i]] = {}
        for j in range(len(graph_adjacency[i])):
            if graph_adjacency[i][j] != INF:
                graph_dict[graph_mapper[i]][graph_mapper[j]] = graph_adjacency[i][j]
    return graph_dict


def dictmap_to_adjacency(graph_dictmap, graph_mapper):
    graph_mapper_re = dict(zip(graph_mapper.values(), graph_mapper.keys()))
    print(graph_mapper_re)


def main():
    graph_dict = adjacency_to_dictmap(graph, graph_mapper)
    import pprint
    pprint.pprint(graph_dict)


if __name__ == '__main__':
    main()

運行結果:
avater

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章