1. 程式人生 > >leetcode 847. Shortest Path Visiting All Nodes 無向連通圖遍歷最短路徑

leetcode 847. Shortest Path Visiting All Nodes 無向連通圖遍歷最短路徑

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 無向連通圖遍歷最短路徑