概念:
-
歐拉回路: 一筆畫, 起點等於終點.
-
歐拉路徑: 一筆畫, 起點可以不等於終點.(條件更加寬松).
-
歐拉圖: 存在歐拉回路的圖.
-
半歐拉圖: 僅存在歐拉路徑的圖.

找歐拉回路
存在的充要條件
A.判斷歐拉通路是否存在的方法
有向圖:圖連通, 有一個頂點出度大入度1, 有一個頂點入度大出度1, 其余都是出度=入度.
無向圖:圖連通, 只有兩個頂點是奇數度, 其余都是偶數度的.
B.判斷歐拉回路是否存在的方法
有向圖:圖連通, 所有的頂點出度=入度.
無向圖:圖連通, 所有頂點都是偶數度.
特殊情況:孤立點, 孤立點沒有邊相連, 沒有影響, 求解歐拉回路的時候可以直接刪掉.
下面進行簡單的證明:
起點終點為奇數度的, 先從起點到終點連任意一條邊, 可以得到一個皆為偶數度的圖. 一個皆為偶數度的圖的必定不可能是一棵樹, 必定存在一個簡單環. 得到一個簡單環之后, 將該環從圖中刪去, 仍然可以得到一個皆為偶數度的圖, 如此反復, 最終可以將原圖分解為由許多個環組成的圖.
可以發現各個環之間不存在公共邊, 且一定可以通過某些點進行連接, 因此, 我們總是可以找到一條歐拉路徑去遍歷所有的邊.
DFS
DFS天然具有拓撲的特性, 可以得到對一個歐拉圖進行DFS, 回溯的時候將邊彈入棧中, 就可以天然得到一個歐拉路徑. 看下面代碼.
歐拉回路為了保證時間復雜度的性能, 需要將遍歷過的邊進行刪除, 為了使后續訪問的刪點過程可以影響前面的遍歷, 需要用到引用.
代碼:
//記錄邊的路徑
void Euler(int u) {
for (int &i = h[u]; ~i; i = ne[i]) {//改為引用
int t = i / 2 + 1;
if (used[t]) continue; // coloring
used[t] = true;
if (i & 1) t = -t;
Euler(e[i]);
ans[++tot] = t;
if (i == -1) break; //prevent ne[-1]
int t = i + 1;
if (used[t]) continue; // coloring
used[t] = true;
Euler(e[i]);
ans[++tot] = t;
if (i == -1) break; //prevent ne[-1]
}
}
void Euler(int u) {
for (int &i = h[u]; ~i; i = ne[i]) {
int t = i / 2 + 1, v = e[i]; //undir
int t = i + 1, v = e[i]; //dir
if (used[t]) continue;
used[t] = true;
Euler(v);
ans[++tot] = v;
if (i == -1) break;
}
}
