歐拉圖
本頁面將簡要介紹歐拉圖的概念、實現和應用。
定義
- 歐拉回路:通過圖中每條邊恰好一次的迴路
- 歐拉通路:通過圖中每條邊恰好一次的通路
- 歐拉圖:具有歐拉回路的圖
- 半歐拉圖:具有歐拉通路但不具有歐拉回路的圖
性質
歐拉圖中所有頂點的度數都是偶數。
若 \(G\) 是歐拉圖,則它為若干個環的並,且每條邊被包含在奇數個環內。
判別法
- 無向圖是歐拉圖當且僅當:
- 非零度頂點是連通的
- 頂點的度數都是偶數
- 無向圖是半歐拉圖當且僅當:
- 非零度頂點是連通的
- 恰有 2 個奇度頂點
- 有向圖是歐拉圖當且僅當:
- 非零度頂點是強連通的
- 每個頂點的入度和出度相等
- 有向圖是半歐拉圖當且僅當:
- 非零度頂點是弱連通的
- 至多一個頂點的出度與入度之差為 1
- 至多一個頂點的入度與出度之差為 1
- 其他頂點的入度和出度相等
求歐拉回路或歐拉路
Fleury 算法
也稱避橋法,是一個偏暴力的算法。
算法流程為每次選擇下一條邊的時候優先選擇不是橋的邊。
一個廣泛使用但是錯誤的實現方式是先 Tarjan 預處理橋邊,然後再 DFS 避免走橋。但是由於走圖過程中邊會被刪去,一些非橋邊會變為橋邊導致錯誤。最簡單的實現方法是每次刪除一條邊之後暴力跑一遍 Tarjan 找橋,時間複雜度是 \(\Theta(m(n+m))=\Theta(m^2)\)。複雜的實現方法要用到動態圖等,實用價值不高。
Hierholzer 算法
也稱逐步插入迴路法。
過程
算法流程為從一條迴路開始,每次任取一條目前回路中的點,將其替換為一條簡單迴路,以此尋找到一條歐拉回路。如果從路開始的話,就可以尋找到一條歐拉路。
實現
Hierholzer 算法的暴力實現如下:
性質
這個算法的時間複雜度約為 \(O(nm+m^2)\)。實際上還有複雜度更低的實現方法,就是將找回路的 DFS 和 Hierholzer 算法的遞歸合併,邊找回路邊使用 Hierholzer 算法。
如果需要輸出字典序最小的歐拉路或歐拉回路的話,因為需要將邊排序,時間複雜度是 \(\Theta(n+m\log m)\)(計數排序或者基數排序可以優化至 \(\Theta(n+m)\))。如果不需要排序,時間複雜度是 \(\Theta(n+m)\)。
應用
有向歐拉圖可用於計算機譯碼。
設有 \(m\) 個字母,希望構造一個有 \(m^n\) 個扇形的圓盤,每個圓盤上放一個字母,使得圓盤上每連續 \(n\) 位對應長為 \(n\) 的符號串。轉動一週(\(m^n\) 次)後得到由 \(m\) 個字母產生的長度為 \(n\) 的 \(m^n\) 個各不相同的符號串。
構造如下有向歐拉圖:
設 \(S = \{a_1, a_2, \cdots, a_m\}\),構造 \(D=\langle V, E\rangle\),如下:
\(V = \{a_{i_1}a_{i_2}\cdots a_{i_{n-1}} |a_i \in S, 1 \leq i \leq n - 1 \}\)
\(E = \{a_{j_1}a_{j_2}\cdots a_{j_{n-1}}|a_j \in S, 1 \leq j \leq n\}\)
規定 \(D\) 中頂點與邊的關聯關係如下:
頂點 \(a_{i_1}a_{i_2}\cdots a_{i_{n-1}}\) 引出 \(m\) 條邊:\(a_{i_1}a_{i_2}\cdots a_{i_{n-1}}a_r, r=1, 2, \cdots, m\)。
邊 \(a_{j_1}a_{j_2}\cdots a_{j_{n-1}}\) 引入頂點 \(a_{j_2}a_{j_3}\cdots a_{j_{n}}\)。
這樣的 \(D\) 是連通的,且每個頂點入度等於出度(均等於 \(m\)),所以 \(D\) 是有向歐拉圖。
任求 \(D\) 中一條歐拉回路 \(C\),取 \(C\) 中各邊的最後一個字母,按各邊在 \(C\) 中的順序排成圓形放在圓盤上即可。
例題
洛谷 P2731 騎馬修柵欄
給定一張有 500 個頂點的無向圖,求這張圖的一條歐拉路或歐拉回路。如果有多組解,輸出最小的那一組。
在本題中,歐拉路或歐拉回路不需要經過所有頂點。
邊的數量 m 滿足 \(1\leq m \leq 1024\)。
解題思路
用 Fleury 算法解決本題的時候只需要再貪心就好,但是由於複雜度不對,所以要換用 Hierholzer 算法。
保存答案可以使用 std::stack<int>,因為如果找的不是迴路的話必須將那一部分放在最後。
注意,不能使用鄰接矩陣存圖,否則時間複雜度會退化為 \(\Theta(nm)\)。由於需要將邊排序,建議使用前向星或者 std::vector 存圖。示例代碼使用 std::vector。
示例代碼
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 | |
習題
本页面最近更新:,更新历史
发现错误?想一起完善? 在 GitHub 上编辑此页!
本页面贡献者:OI-wiki
本页面的全部内容在 CC BY-SA 4.0 和 SATA 协议之条款下提供,附加条款亦可能应用