欧拉回路
将所有边全部经过的路径称为欧拉路,起点终点还一样,就可以称为欧拉回路。
判定:
-
有向图欧拉路:弱连通图中每个点入度 = 出度 或者有一个点入度比出度小一,有一个点入度比出度大一。
-
有向图欧拉回路:弱连通图中每个点入度 = 出度
-
无向图欧拉路:联通,且最多有两个点度数为奇数。
-
无向图欧拉回路:联通,且所有点度数均为偶数。
找方案
找到起点开始 DFS,每次找一条未遍历过的出边走过去。DFS 结束后将当前点放入栈中。最后栈内序列(的逆序列)即为一组解。
复杂度:\(O(nm)\),用弧优化能优化到 \(O(n+m)\),但是需要 &i
而不是 hcur[cur]
,否则仍为 \(O(nm)\)。
代码:(以无向图欧拉回路为例)
int stk[N], stop;
bool evis[NN];
void dfs(int cur) {
for (int &i = head[cur]; i; i = e[i].nxt) {
if (evis[i]) continue;
evis[i] = evis[i ^ 1] = true;
dfs(e[i].to);
}
stk[++stop] = cur;
}
应用
对无向图跑欧拉回路能给无向边定向,并且定向后每个点的入度出度相等。借助这个特点可以做一些类似匹配的构造题(如Mike and Fish 和 Two Trees)
模板
bool evis[N << 1];
int stk[N << 1], stop;
void dfs(int cur) {
for (int &i = head[cur]; i; i = e[i].nxt) {
if (evis[i] || evis[dui[i]]) continue;
evis[i] = true;
int tmp = e[i].id;
dfs(e[i].to);
stk[++stop] = tmp;
}
}
int main() {
read(t);
read(n), read(m); tot = n;
for (int i = 1; i <= n; ++i) fath[i] = i;
for (int i = 1; i <= m; ++i) {
int u, v; read(u), read(v);
if (t == 1) addedge(u, v, i), addedge(v, u, -i), dui[i * 2 - 1] = i * 2, dui[i * 2] = i * 2 - 1;
else addedge(u, v, i);
merge(u, v);
}
for (int i = 1; i <= n; ++i) if (!ind[i] && !outd[i]) --tot;
if (tot > 1) Fail();
if (t == 1) {
for (int i = 1; i <= n; ++i) if (ind[i] & 1) Fail();
} else {
for (int i = 1; i <= n; ++i) if (ind[i] != outd[i]) Fail();
}
for (int i = 1; i <= n; ++i) if (ind[i] || outd[i]) dfs(i);
puts("YES");
while (stop) printf("%d ", stk[stop]), --stop;
puts("");
return 0;
}