← 回首頁

圖論雜項(歐拉路徑 / 2-SAT)

小時候玩過「一筆畫」嗎?筆不離紙、每條線只能描一次,把整個圖形畫完——這就是歐拉路徑(Euler Path)要解的事: 一趟走遍所有邊、不重複。另一個看似八竿子打不著的難題是2-SAT:一堆事情每件都只能二選一(要 A 或要 B), 選項之間又互相牽制(選了這個就不能選那個),問到底喬不喬得出一組彼此不打架的安排。 神奇的是,這兩題最後都能「畫成一張圖」再交給電腦去走。下面你會看到它們各自怎麼在圖上一步步逼出答案。

兩個乍看無關、實際都靠圖結構解決的經典問題:歐拉路徑(Euler Path,Hierholzer 演算法)要找一條「一筆畫」路徑, 每條邊恰走一次,用顯式棧邊走邊刪邊、走到死路就彈棧回填路徑; 2-SAT則是把布林變數的二元子句可滿足性問題「翻譯」成有向圖上的蘊含邊, 再靠 Tarjan 強連通分量一次性判定矛盾並決定每個變數的賦值。一個是「圖論問題直接在圖上求解」, 一個是「把邏輯問題轉成圖論問題再求解」。

1. 歐拉路徑 Euler Path(Hierholzer)

先計算各頂點度數:奇度頂點數須為 0(歐拉迴路)或 2(歐拉路徑)且圖連通,否則無解。 決定起點後入棧;每次看棧頂節點 v,若還有剩餘邊就取 id 最小的鄰居 u、刪除邊 v-u(雙向)、u 入棧; 若 v 已無剩餘邊,就彈棧並把 v 加入路徑。棧清空後反轉路徑,即為歐拉路徑(或迴路)。

固定示範圖(同 euler-path.test.js EULER_GRAPH,5 節點無向圖,恰 2 個奇度頂點 2,3,起點=2)
已走過邊數(edgesUsed):0
紅色為棧頂正在處理的節點;藍框為目前在棧上的節點;灰暗為已彈棧進入路徑的節點;綠色粗邊為已走過(已刪除)的邊,累積顯示;節點上方數字為剩餘度數。

棧內容(底 → 頂,頂為下一個處理)

路徑面板(正序,最終即為歐拉路徑)

2. 2-SAT(蘊含圖 + Tarjan SCC)

每個變數 x 拆成兩個 literal 節點 x 與 ¬x;每條子句 (a∨b) 等價於「¬a⟹b」與「¬b⟹a」兩條蘊含邊, 建成蘊含圖後跑一次 Tarjan SCC(同 dfn/low + 顯式棧,依 id 升序拜訪鄰居)。 若某個變數的 x 與 ¬x 落在同一組 SCC 即矛盾、判定無解;否則逐變數依 sccId[x] 與 sccId[¬x] 的大小決定賦值(sccId 值愈小代表在 SCC 縮點後的拓撲序中愈晚,即 sccId 較小者為真)。

固定示範案例(同 two-sat.test.js TWOSAT_INSTANCE,3 變數 4 子句:(x0∨x1)、(¬x0∨x2)、(¬x1∨¬x2)、(x1∨x2),可滿足)
DFS 造訪次數(visits):0
紅色為當前 DFS 處理的 literal 節點;藍框為 Tarjan 棧上待定節點;綠色為已併入某組 SCC;綠色粗框為本幀剛彈棧完成的 SCC 成員(Phase 2)或正在檢查/賦值的變數對(Phase 3);節點上方數字為 dfn/low(未定案)或 sccId(已定案)。

子句面板

Tarjan 棧內容(底 → 頂)

sccId 表(literal → 所屬 SCC 編號,- 表示尚未定案)

賦值面板(變數 → 值,? 表示尚未判定)

可滿足性

判定中