進階圖論題目: Leetcode #847 Shortest Path Visiting All Nodes

更新於 發佈於 閱讀時間約 7 分鐘
raw-image

這題的題目在這裡:

題目會給定我們一張圖和對應的相鄰矩陣,要求我們返回一筆畫拜訪所有節點的最短路徑長,起終點不拘。


測試範例:

Example 1:

raw-image
Input: graph = [[1,2,3],[0],[0],[0]]
Output: 4
Explanation: One possible path is [1,0,2,0,3]

Example 2:

raw-image
Input: graph = [[1],[0,2,4],[1,3,4],[2],[1,2]]
Output: 4
Explanation: One possible path is [0,1,4,2,3]

約束條件:

Constraints:

  • n == graph.length
  • 1 <= n <= 12
  • 0 <= graph[i].length < n
  • graph[i] does not contain i.
  • If graph[a] contains b, then graph[b] contains a.
  • The input graph is always connected.

演算法:

回顧一些圖論的基本演算法,BFS, DFS, MST最小生成樹, Shortest Path給定起點的最短路徑…等。哪個比較適合呢?

BFS最適合? 為什麼,因為BFS先天具有點波源擴散的特質,由起點往外擴散,逐層探索,當滿足終止條件時(以本題目為例,就是拜訪過所有節點),擴散層數 = 最短路徑。

這題的困難點又在哪呢? 因為起終點不固定,但是又要求必須拜訪所有節點

所以,一開始初始化的時候,必須把所有節點都納入Source 起始點。

(因為事先不知道從哪個節點走,可以產生最短的一筆畫路徑,所有的節點都必須納入考量。)

traversal_queue = deque( [(node_idx, 1 << node_idx , 0) for node_idx in range(n) ] )

接著,必須防止進入迴圈死循環,因為題目輸入的圖Grpah,可能帶有環路(Cycle)


所以,在設計visited set和推入traversal queue時,必須同步考慮到當下的搜索狀態search state。當BFS 進行中,必須檢查(node index, search state)沒有重複,才走下一步。

visited = { (node_idx, 1 << node_idx ) for node_idx in range(n) }


最後,就是設定終止條件,題目已經給定是一筆畫路徑,而且必須拜訪所有節點。所以,如果當下search state的bit mask已經拜訪過所有節點,則BFS演算法抵達終止條件,當下的搜索步長 = 擴散層數 = 一筆畫拜訪所有節點的最短路徑長。

    # We've visited all nodes in graph G at least once
   if cur_state == all_node_visited:
    return path_length

程式碼:

class Solution:
 def shortestPathLength(self, graph: List[List[int]]) -> int:

  # n = total node count = height of adjacency matrix
  n = len(graph)

  # Initialize traversal queue
  # parameter of tuple: (node idx, state mask, visiting path length)
  traversal_queue = deque( [(node_idx, 1 << node_idx , 0) for node_idx in range(n) ] )

  # parameter of visited tuple: (node index, search state mask)
  visited = { (node_idx, 1 << node_idx ) for node_idx in range(n) }

  # Mask of all node visited
  all_node_visited = (1 << n) - 1

  # Launch BFS traversal from each node in graph G as source
  while traversal_queue:

   cur_node, cur_state, path_length = traversal_queue.popleft()

   # We've visited all nodes in graph G at least once
   if cur_state == all_node_visited:
    return path_length
   
   # Visit neighbor of current node
   for neighbor_idx in graph[cur_node]:

    next_state = cur_state | (1 << neighbor_idx)
    next_length = path_length + 1

    # If pair (neighbor index, next state) is not seen before
    if (neighbor_idx, next_state) not in visited:

     traversal_queue.append( (neighbor_idx, next_state, next_length) )
     visited.add( (neighbor_idx, next_state) )

  
  return -1



令n = 輸入圖中的總節點數

時間複雜度:

O( n² * 2^n )

BFS 圖論演算法基本複雜度為O( V + E ) = O( n + n² ),

當稠密圖時,Edge最多可以有C(n,2)條邊 = O( n² )

此外,在BFS探索的每一步中,需要額外紀錄O(2^n) seach state mask搜索狀態的遮罩。

因為總共有n個節點每個節點兩種可能(拜訪過 或 沒拜訪過),遮罩最多有O(2^n)種不同狀態。


空間複雜度:

O( n * 2^n )

耗費在Traversal queue 和 visited set上,最多有n個節點,拜訪每個節點當下伴隨最多2^n種狀態。


Reference:

[1] Python O( (n²) * (2^n) ) by BFS + bitmask — Shortest Path Visiting All Nodes — LeetCode



avatar-img
91會員
425內容數
由有業界實戰經驗的演算法工程師, 手把手教你建立解題的框架, 一步步寫出高效、清晰易懂的解題答案。 著重在讓讀者啟發思考、理解演算法,熟悉常見的演算法模板。 深入淺出地介紹題目背後所使用的演算法意義,融會貫通演算法與資料結構的應用。 在幾個經典的題目融入一道題目的多種解法,或者同一招解不同的題目,擴展廣度,並加深印象。
留言0
查看全部
avatar-img
發表第一個留言支持創作者!
Coin Change + DP 策略_Leetcode 面試題 上機考 題目 詳細解說
Coin Change + DP 策略_Leetcode 面試題 上機考 題目 詳細解說
你可能也想看
Google News 追蹤
Thumbnail
大家好,我是woody,是一名料理創作者,非常努力地在嘗試將複雜的料理簡單化,讓大家也可以體驗到料理的樂趣而我也非常享受料理的過程,今天想跟大家聊聊,除了料理本身,料理創作背後的成本。
Thumbnail
哈囉~很久沒跟各位自我介紹一下了~ 大家好~我是爺恩 我是一名圖文插畫家,有追蹤我一段時間的應該有發現爺恩這個品牌經營了好像.....快五年了(汗)時間過得真快!隨著時間過去,創作這件事好像變得更忙碌了,也很開心跟很多厲害的創作者以及廠商互相合作幫忙,還有最重要的是大家的支持與陪伴🥹。  
Thumbnail
嘿,大家新年快樂~ 新年大家都在做什麼呢? 跨年夜的我趕工製作某個外包設計案,在工作告一段落時趕上倒數。 然後和兩個小孩過了一個忙亂的元旦。在深夜時刻,看到朋友傳來的解籤網站,興致勃勃熬夜體驗了一下,覺得非常好玩,或許有人玩過了,但還是想寫上來分享紀錄一下~
隨機漫步看似簡單,但卻是模擬許多自然界現象的基礎,相關的觀念及程式實作方式,對於瞭解亂數、機率、Perlin noise等工具,會有相當大的幫助。
Thumbnail
Node 對我來說一直是很似懂非懂的概念,因為沒有實際可見的數字或字串實物可以觀察中間步驟,比起其他解題抽象許多。以下解題方法來自網友與 GPT 提供的答案,我想在本文中嘗試自己做視覺化圖解,說明 CodeWars - Can you get the loop ? 的解題思路。
Thumbnail
本篇文章介紹了路徑的概念和兩種不同的路徑運用。這些知識對於網頁開發非常重要,能夠幫助網站開發者更好地管理資源文件的位置。文章通過實際例子和相對路徑的範例來解釋這些概念。希望通過這篇文章,讀者能夠清楚地瞭解路徑的概念,並在日後的開發中能夠靈活運用。
Thumbnail
上篇進一步認識基本的圖形架構與三大 Graph 算法,那首先從 shortest path 開始,我們會陸續去理解這些算法,以及可能的應用,如果還沒有看過上一篇的,可以點以下連結~那我們就開始吧! 【圖論Graph】Part1:初探圖形與圖形演算法之應用
Thumbnail
本篇文章深入介紹了圖形的基本概念、組成和應用。從圖形的基本組成,到圖的類型與種類,再到圖形演算法的三大類型,本文將接續圖形領域的深入學習,並分享了對圖形的初步認識和學習方向的小心得。希望對正在學習圖形的人有所幫助。
Thumbnail
解決電腦上遇到的問題、證明正確性、探討效率 並且很著重溝通,說服別人你做的事是正確且有效率的。 內容: 計算模型、資料結構介紹、演算法介紹、時間複雜度介紹。
基本數學吧,兩點之間最短的距離是直線,我們都被教育的很好。但是人生的路走著走著,我發現自己好像想錯了。我要的是最快,並不是最近。因為曾經以為最近就是最快,所以日子難免頭破血流。大家都擠在最明顯的最近的道路上時,能不能殺出一條血路,變成了惟一的問題,你可能都忘了,為什麼要走在這條路上。 有人說:就算
Thumbnail
大家好,我是woody,是一名料理創作者,非常努力地在嘗試將複雜的料理簡單化,讓大家也可以體驗到料理的樂趣而我也非常享受料理的過程,今天想跟大家聊聊,除了料理本身,料理創作背後的成本。
Thumbnail
哈囉~很久沒跟各位自我介紹一下了~ 大家好~我是爺恩 我是一名圖文插畫家,有追蹤我一段時間的應該有發現爺恩這個品牌經營了好像.....快五年了(汗)時間過得真快!隨著時間過去,創作這件事好像變得更忙碌了,也很開心跟很多厲害的創作者以及廠商互相合作幫忙,還有最重要的是大家的支持與陪伴🥹。  
Thumbnail
嘿,大家新年快樂~ 新年大家都在做什麼呢? 跨年夜的我趕工製作某個外包設計案,在工作告一段落時趕上倒數。 然後和兩個小孩過了一個忙亂的元旦。在深夜時刻,看到朋友傳來的解籤網站,興致勃勃熬夜體驗了一下,覺得非常好玩,或許有人玩過了,但還是想寫上來分享紀錄一下~
隨機漫步看似簡單,但卻是模擬許多自然界現象的基礎,相關的觀念及程式實作方式,對於瞭解亂數、機率、Perlin noise等工具,會有相當大的幫助。
Thumbnail
Node 對我來說一直是很似懂非懂的概念,因為沒有實際可見的數字或字串實物可以觀察中間步驟,比起其他解題抽象許多。以下解題方法來自網友與 GPT 提供的答案,我想在本文中嘗試自己做視覺化圖解,說明 CodeWars - Can you get the loop ? 的解題思路。
Thumbnail
本篇文章介紹了路徑的概念和兩種不同的路徑運用。這些知識對於網頁開發非常重要,能夠幫助網站開發者更好地管理資源文件的位置。文章通過實際例子和相對路徑的範例來解釋這些概念。希望通過這篇文章,讀者能夠清楚地瞭解路徑的概念,並在日後的開發中能夠靈活運用。
Thumbnail
上篇進一步認識基本的圖形架構與三大 Graph 算法,那首先從 shortest path 開始,我們會陸續去理解這些算法,以及可能的應用,如果還沒有看過上一篇的,可以點以下連結~那我們就開始吧! 【圖論Graph】Part1:初探圖形與圖形演算法之應用
Thumbnail
本篇文章深入介紹了圖形的基本概念、組成和應用。從圖形的基本組成,到圖的類型與種類,再到圖形演算法的三大類型,本文將接續圖形領域的深入學習,並分享了對圖形的初步認識和學習方向的小心得。希望對正在學習圖形的人有所幫助。
Thumbnail
解決電腦上遇到的問題、證明正確性、探討效率 並且很著重溝通,說服別人你做的事是正確且有效率的。 內容: 計算模型、資料結構介紹、演算法介紹、時間複雜度介紹。
基本數學吧,兩點之間最短的距離是直線,我們都被教育的很好。但是人生的路走著走著,我發現自己好像想錯了。我要的是最快,並不是最近。因為曾經以為最近就是最快,所以日子難免頭破血流。大家都擠在最明顯的最近的道路上時,能不能殺出一條血路,變成了惟一的問題,你可能都忘了,為什麼要走在這條路上。 有人說:就算