深度優先搜尋-Roads
阿新 • • 發佈:2020-07-08
N個城市,編號1到N。城市間有R條單向道路。
每條道路連線兩個城市,有長度和過路費兩個屬性。
Bob只有K塊錢,他想從城市1走到城市N。問最短共需要走多長的路。
如果到不了N,輸出-1
2<=N<=100
0<=K<=10000
1<=R<=10000
每條路的長度 L, 1 <= L <= 100,每條路的過路費T , 0 <= T <= 100
輸入:
K N R s1
e1 L1 T1
s1 e2 L2 T2
...
sR eR LR TR
s e是路起點和終點
解題思路:從城市 1開始深度優先遍歷整個圖,找到所有能過到達 N 的走法,
選一個最優的。
最優性剪枝:
1) 如果當前已經找到的最優路徑長度為L ,那麼在繼續搜尋的過程中,總長度已經大於
等於L的走法,就可以直接放棄,不用走到底了
儲存中間計算結果用於最優性剪枝:
2) 用midL[k][m] 表示:走到城市k時總過路費為m的條件下,最優路徑的長度。若在
後續的搜尋中,再次走到k時,如果總路費恰好為m,且此時的路徑長度已經超過
midL[k][m],則不必再走下去了。
輸入:
5
6
7
1 2 2 3
2 4 3 3
3 4 2 4
1 3 4 1
4 6 2 1
3 5 2 0
5 4 3 2
輸出:
11
python演算法實現:
1 INF = float("inf") 2 # k-錢,N-終點,R-共有多少條邊 3 K, N, R = 0, 0, 0 4 # 當前找到的最優路徑的長度 5 minLen = INF6 # 正在走的路徑的長度、正在走的路徑的花銷 7 totalLen, totalCost = 0, 0 8 # 城市是否已經走過的標記 9 visited = [] 10 nodeList = list() 11 # minL[i][j]表示從1到i點的,花銷為j的最短路的長度 12 minL = [[INF for cols in range(10100)] for rows in range(110)] 13 14 # 儲存鄰接表的class結構 15 class Node(): 16 def __init__(self, code, data=None, bnext=None):17 self.code = code 18 self.data = dict() 19 self.bnext = list() 20 21 22 # 從s點開始向N行走 23 def dfs(s): 24 global K, N, minLen, totalLen, totalCost, nodeList, minL 25 # 說明走到終點 26 if s == N: 27 minLen = min(minLen, totalLen) 28 return 29 #對s有多少條可以走出去的邊進行遍歷 30 # 獲取list中s與code相等的索引位置 31 index = 0 32 # 在nodeList列表中找s起始點的索引位置 33 for i, item in enumerate(nodeList): 34 if s == item.code: 35 index = i 36 break 37 # 對起始點的所有的相鄰點都進行遍歷 38 for i, item in enumerate(nodeList[index].bnext): 39 # 走當前點的費用大於手裡有的總金額,不能走,遍歷下一條路 40 # 也就是錢不夠用了,data是字典,key-頂點,value-列表,索引0:長度,索引1:花費金額 41 if totalCost + nodeList[index].data.get(item)[1] > K: 42 continue 43 # 如果該點沒有訪問過 44 if visited[item] == 0: 45 # 如果totalLen+當前點的路徑長度大於之前的最優路徑長度,說明不是 46 # 最優的路徑,所以之後的路不需要再遞迴走了 47 if totalLen + nodeList[index].data.get(item)[0] >= minLen: 48 continue 49 # 如果走到當前節點花費的價錢相同,如果路徑更長的話,則不繼續往下走 50 # 第2種最優性剪枝 51 if totalLen + nodeList[index].data.get(item)[0] > minL[item][totalCost + nodeList[index].data.get(item)[1]]: 52 continue 53 minL[item][totalCost + nodeList[index].data.get(item)[1]] = totalLen + nodeList[index].data.get(item)[0] 54 totalLen += nodeList[index].data.get(item)[0] 55 totalCost += nodeList[index].data.get(item)[1] 56 visited[item] = 1 57 dfs(item) 58 # 本條路線走完該點後,需要重新把點的標記、長度和花費都重置, 59 # 因為下次新的路線可能還會走該點 60 visited[item] = 0 61 totalLen -= nodeList[index].data.get(item)[0] 62 totalCost -= nodeList[index].data.get(item)[1] 63 return 0 64 65 66 def main(): 67 global K, N, R, visited, minLen, nodeList 68 K, N, R = map(int, input().split()) 69 visited = [0 for i in range(N+1)] 70 # 構造鄰接表 71 for i in range(R): 72 s, t, l, c = map(int, input().split()) 73 in_flag = False 74 tempNode = Node(s) 75 tempNode.bnext.append(t) 76 tempNode.data.update({t: [l, c]}) 77 if len(nodeList) > 0: 78 for j in nodeList: 79 if s == j.code: 80 in_flag = True 81 break 82 if in_flag: 83 j.bnext.append(t) 84 j.data.update({t: [l, c]}) 85 else: 86 nodeList.append(tempNode) 87 else: 88 nodeList.append(tempNode) 89 tempNode = Node(0) 90 tempNode.bnext.append(0) 91 tempNode.data.update({0: [0, 0]}) 92 nodeList.insert(0, tempNode) 93 # 因為從1號點開始,所以先把1號點標誌已走過 94 visited[1] = 1 95 # 從1號點開始深度搜索 96 dfs(1) 97 # 如果minLen小於無窮大,說明找到了最優的路徑,否則輸出-1 98 if minLen < float("inf"): 99 print(minLen) 100 else: 101 print(-1) 102 return 0 103 104 105 if __name__ == '__main__': 106 main()