1. 程式人生 > >分支限界法:單源最短路徑--dijkstra演算法

分支限界法:單源最短路徑--dijkstra演算法

單源最短路徑–dijkstra演算法

前面已經多次介紹過dijkstra演算法是貪心演算法,是動態規劃,實際上可以從分支限界的角度來理解;

分支限界法

分支限界法,實際上就是回溯法,一般意義的回溯法是基於深度優先搜尋,也可以配合限界函式剪枝,通常分支限界法基於寬度優先搜尋,通過佇列或者優先順序佇列實現。
剪枝的策略:不相鄰的邊剪掉,二是結點控制關係的路徑剪掉,兩條路徑到達同一個頂點,在解空間樹上是屬於兩條不同的路徑,把路徑長的節點後面的分支剪掉

程式碼實現如下:

import numpy as np
import heapq
class dijkstra:
    def
__init__(self,graph,start): # 鄰接表 self.graph = graph # 頂點個數 self.num = len(graph) #源點 self.start = start # 已知最短路徑,又叫當前最優值,並初始化 self.dist = {vertex:np.Inf for vertex in graph} self.dist[start] = 0.0 # 初始化優先順序佇列 self.
queue = [] heapq.heappush(self.queue,(0.0,start)) #追蹤解 self.parent = {start:None} def shortest_Path(self): while self.queue: #取出根節點 enode = heapq.heappop(self.queue) distance = enode[0] vertex = enode[
1] # 取鄰接的邊,實際上過濾了不相鄰的邊 # 這裡可以寫成 for j in range(self.num), # 看成完全n叉樹,也可以看成隨機叉樹的處理 for j in self.graph[vertex].keys(): # 他們都叫這個為控制約束,兩條到某同一點的路徑,長的那一條後面就被剪掉了 # 也就是貪心法裡面的貪心策略 if distance + self.graph[vertex][j] < self.dist[j] : self.dist[j] = distance + self.graph[vertex][j] self.parent[j] = vertex heapq.heappush(self.queue,(self.dist[j],j)) def print_Result(self): print(self.parent) print(self.dist)

對比基於貪心策略優先順序佇列實現方式,就多了一步:if v not in visit,也就是標記那些點已經達到了最短距離,就沒有必要再算了,做了進一步剪枝:

def dijkstra_test(graph,start):
    pqueue = []
    heapq.heappush(pqueue,(0.0,start))
    
    visit = set()
    parent = {start:None}
    distance = {vertex:np.Inf for vertex in graph}
    distance[start] = 0.0
    
    
    while pqueue:
        pair = heapq.heappop(pqueue)        
        dist = pair[0]
        vertex = pair[1]
        visit.add(vertex)
        
        edges = graph[vertex]
        for v in edges:
            if v not in visit:
                if dist + graph[vertex][v] < distance[v]:
                    heapq.heappush(pqueue,(dist + graph[vertex][v],v))
                    distance[v] = dist + graph[vertex][v]
                    parent[v] = vertex 
                    
    print(parent)
    print(distance)        

對比測試結果:

#%%
g = {'A':{'B':1,'C':2},
     'B':{'A':1,'C':3,'D':4},
     'C':{'A':2,'B':3,'D':5,'E':6},
     'D':{'B':4,'C':5,'E':7,'F':8},
     'E':{'C':6,'D':7,'F':9},
     'F':{'D':8,'E':9,'G':10},
     'G':{'F':10}
    }

dij = dijkstra(g,'D')
dij.shortest_Path()
dij.print_Result()

dijkstra_test(g,'D')

{'D': None, 'B': 'D', 'C': 'D', 'E': 'D', 'F': 'D', 'A': 'B', 'G': 'F'}
{'A': 5.0, 'B': 4.0, 'C': 5.0, 'D': 0.0, 'E': 7.0, 'F': 8.0, 'G': 18.0}
{'D': None, 'B': 'D', 'C': 'D', 'E': 'D', 'F': 'D', 'A': 'B', 'G': 'F'}
{'A': 5.0, 'B': 4.0, 'C': 5.0, 'D': 0.0, 'E': 7.0, 'F': 8.0, 'G': 18.0}