1 # Bellman-Ford核心算法 2 # 對於一個包含n個頂點,m條邊的圖, 計算源點到任意點的最短距離 3 # 循環n-1輪,每輪對m條邊進行一次松弛操作 4 5 # 定理: 6 # 在一個含有n個頂點的圖中,任意兩點之間的最短路徑最多包含n-1條邊 7 # 最短路徑肯定是一個不包含回路的簡單路徑(回路包括正權回路與負權回路) 8 # 1. 如果最短路徑中包含正權回路,則去掉這個回路,一定可以得到更短的路徑 9 # 2. 如果最短路徑中包含負權回路,則每多走一次這個回路,路徑更短,則不存在最短路徑 10 # 因此最短路徑肯定是一個不包含回路的簡單路徑,即最多包含n-1條邊,所以進行n-1次松弛即可 11 12 13 G = {1:{1:0, 2:-3, 5:5}, 14 2:{2:0, 3:2}, 15 3:{3:0, 4:3}, 16 4:{4:0, 5:2}, 17 5:{5:0}} 18 19 20 21 def getEdges(G): 22 """ 輸入圖G,返回其邊與端點的列表 """ 23 v1 = [] # 出發點 24 v2 = [] # 對應的相鄰到達點 25 w = [] # 頂點v1到頂點v2的邊的權值 26 for i in G: 27 for j in G[i]: 28 if G[i][j] != 0: 29 w.append(G[i][j]) 30 v1.append(i) 31 v2.append(j) 32 return v1,v2,w 33 34 class CycleError(Exception): 35 pass 36 37 def Bellman_Ford(G, v0, INF=999): 38 v1,v2,w = getEdges(G) 39 40 # 初始化源點與所有點之間的最短距離 41 dis = dict((k,INF) for k in G.keys()) 42 dis[v0] = 0 43 44 # 核心算法 45 for k in range(len(G)-1): # 循環 n-1輪 46 check = 0 # 用於標記本輪松弛中dis是否發生更新 47 for i in range(len(w)): # 對每條邊進行一次松弛操作 48 if dis[v1[i]] + w[i] < dis[v2[i]]: 49 dis[v2[i]] = dis[v1[i]] + w[i] 50 check = 1 51 if check == 0: break 52 53 # 檢測負權回路 54 # 如果在 n-1 次松弛之后,最短路徑依然發生變化,則該圖必然存在負權回路 55 flag = 0 56 for i in range(len(w)): # 對每條邊再嘗試進行一次松弛操作 57 if dis[v1[i]] + w[i] < dis[v2[i]]: 58 flag = 1 59 break 60 if flag == 1: 61 # raise CycleError() 62 return False 63 return dis 64 65 v0 = 1 66 dis = Bellman_Ford(G, v0) 67 print dis.values()
