leetcode 847. Shortest Path Visiting All Nodes 無向連通圖遍歷最短路徑
阿新 • • 發佈:2018-07-15
sel shu turn 判斷 lam 最短 額外 動態 訪問
設計最短路徑 用bfs 天然帶最短路徑
每一個狀態是 當前的階段 和已經訪問過的節點
下面是正確但是超時的代碼
class Solution: def shortestPathLength(self, graph): """ :type graph: List[List[int]] :rtype: int """ N=len(graph) Q=collections.deque([(1 << x, x) for x in range(N)]) D=collections.defaultdict(lambda:N*N) for i in range(N): D[1<<i,i]=0 mask=0 #listr= [i for i in range(N)] #random.shuffle(listr) for i in range(N): mask=mask|1<<i while Q: a,h=Q.popleft() d=D[a,h] if(a==mask): return d for child in graph[h]: new_a=a |(1<<child) Q.append((new_a,child)) D[new_a,child]=min(d+1,D[new_a,child])
下面的代碼稍微有優化,但是這種優化是非常好的。(值得思考的優化)
歸根結底是因為沒有考慮好一個狀態是指什麽。
在這裏一個狀態指的是, 以前便利過的節點 和 當前的節點。
有了這個節點狀態
就不用把(到達這個節點的距離作為節點的一部分加入節點中,加入會引起性能損失)
到達這個節點的距離 單獨存入一個數組中做優化 如果同一個狀態後來的距離反而更長 那就丟棄。
class Solution: def shortestPathLength(self, graph): N=len(graph) Q=collections.deque([(1 << x, x) for x in range(N)]) D=collections.defaultdict(lambda:N*N) for i in range(N): D[1<<i,i]=0 mask=0 for i in range(N): mask=mask|1<<i while Q: cover,head=Q.popleft() d=D[cover,head] if(cover==mask): return d for child in graph[head]: new_a=cover |(1<<child) if(d+1<D[new_a,child]): D[new_a,child]=d+1 Q.append((new_a,child))
動態規劃算法
一個數組
state[ cover ][ head ] 表示當前狀態所能達到的最小距離
head 維數的遍歷順序隨意
cover 的遍歷循序是從小到大
因為 new_cover=cover| child 這樣的話內在隱含著一個內在的順序
這樣看來 這個題目有意卡掉了那些沒有註意到這種順序的方法
"relaxation step" (for those familiar with the Bellman-Ford algorithm)
復習 Bellman-Ford algorithm
O(V*E)
1 初始化
2 n-1 次循環 每一個循環遍歷每一個邊 做 relaxtion step
3 額外判斷是否每一條邊都 存在優化空間
第i次循環 實際上是在尋找 單源最短路徑
如果n-1 次循環後還能做 relaxtion step 那麽說明圖中存在 負權回路
leetcode 847. Shortest Path Visiting All Nodes 無向連通圖遍歷最短路徑