← 回首頁

進階圖論(Prim 最小生成樹 / Tarjan 強連通分量)

假設你要在幾個村莊之間鋪水管,想用最少的管線總長把大家全接通、一寸都不浪費——這就是最小生成樹要解的事;Prim 的做法很直覺:從一個村莊出發,每次都挑「接上去最便宜的那一段」,慢慢把整張網路長大。另一種問題不太一樣:在一張「誰指向誰」的有向關係圖裡(像網頁互連、誰追蹤誰),哪些點能彼此繞得回對方、圈成一個小團體?Tarjan 強連通分量只走一趟就把這些圈子一次框出來。下面兩區可以各自逐步播放,看它們怎麼一步步長樹、圈組。

兩個經典但方向不同的圖論演算法:Prim 最小生成樹作用於無向帶權圖,以優先佇列貪心每輪擴充一個「離目前生成樹最近」的節點, 逐步長出一棵涵蓋所有節點、總權重最小的樹;Tarjan 強連通分量(SCC)作用於有向圖, 單次 DFS 搭配 dfn(發現序)/low(可回溯到的最早祖先)與一個顯式棧,在回溯時一次性彈出整組互相可達的節點。 一個是「貪心累加」,一個是「單趟 DFS 分組」。

1. Prim 最小生成樹 Minimum Spanning Tree

以節點 0 為起點,key[0]=0 並將 (0,0) 放入優先佇列;反覆取出佇列中 (w,node) 字典序最小者,若該節點已在 MST 中則跳過(lazy deletion,不主動從佇列刪除舊項); 否則將其併入 MST、累加權重,並檢查其每個不在 MST 中的鄰居,只要邊權小於該鄰居目前的 key 值就更新 key、記錄父節點並重新入佇列。 直到佇列清空,累積的父邊即為最小生成樹。

固定示範圖(6 節點帶權無向圖,同 prim.test.js PRIM_GRAPH;唯一 MST:0-2(3), 1-2(1), 1-3(2), 3-4(2), 4-5(6),總權 14)
已加入 MST 邊數(edgesAdded):0 累計權重(totalWeight):0
紅色為當前處理節點;藍框為優先佇列中待處理(frontier);綠色為已入 MST;綠色粗邊為已確定的 MST 邊(累積顯示);節點上方數字為該節點目前的 key 值(∞ 表示尚未被鬆弛到)。

key 表(各節點目前最小候選邊權,∞ 表示尚未被鬆弛到)

優先佇列內容(依 (w, node) 排序顯示,含 lazy 過期項)

2. Tarjan 強連通分量 Strongly Connected Components

單次 DFS:進入節點 u 時設 dfn[u]=low[u]=time++、將 u 入棧;依 id 升序檢查每個鄰居 v——若 v 未訪問則遞迴後用 low[v] 更新 low[u], 若 v 已訪問且仍在棧上則用 dfn[v] 更新 low[u](代表 v 是還沒結束的祖先,形成環)。 回溯到 u 時若 low[u]==dfn[u],代表 u 是目前這組強連通分量的「根」,將棧一路彈出至 u,彈出的節點即組成一組 SCC。

固定示範圖(8 節點有向圖,同 tarjan-scc.test.js TARJAN_GRAPH;含三個環,SCC 分割:{0,1,2} {3,4} {5,6,7})
DFS 造訪次數(visits):0
紅色為當前 DFS 節點;藍框為棧上待定節點(frontier);綠色為已併入某組 SCC;綠色粗框為本幀剛彈棧完成的 SCC 成員;節點上方數字為 dfn/low。

棧內容(底 → 頂,頂為下一個彈出)

SCC 清單(依發現順序,各組一列)