欧拉路
欧拉路
给定一张无向图,若存在一条从节点\(x\)到节点\(y\)的路径,恰好经过每条边一次(节点可以重复经过),那么称这条路径为\(x\)到\(y\)的欧拉路。
欧拉回路
如果存在一条欧拉路从\(x\)出发并且回到\(x\),那么称这条路径为欧拉回路。存在欧拉回路的无向图被称为欧拉图。
欧拉路的存在性判定
无向图
-
每个节点的度数都是偶数,此时从任意节点出发都存在欧拉回路。
-
除了\(x, y\)两个节点度数为奇数,其他节点度数都为偶数,此时存在以\(x, y\)为起点或终点的欧拉路。
有向图
-
每个节点的入度都等于出度,此时从任意节点出发都存在欧拉回路。
-
除了\(x\)节点出度比入度大\(1\),\(y\)节点入度比出度大\(1\),其他节点入度都等于出度,此时存在以\(x\)为起点,\(y\)为终点的欧拉路。
寻找欧拉路
算法思想十分简单,只需从起点出发\(DFS\),当这个点的还有边可以走,就朝着这条边走,同时标记这条边已经被走过;当这个点的边已经全部走过了,就把这个节点放入栈。
最后栈中元素从上到下的顺序就是这条欧拉路经过的节点。
代码:
void euler (int x) {
for (int i = 1; i <= N; i ++)
if (vis[x][i]) {
vis[x][i] = 0;
vis[i][x] = 0;
euler(i);
}
ans[++ ans[0]] = x;
}
试题
题解
骑马修栅栏
一道模板题。
看完题目,很显然就是要我们求这张图上一条字典序最小欧拉路。
既然要字典序最小,只需要在\(DFS\)时,从小到大去枚举边就行了。
接下来就是确定起点。
如果存在某两个节点度数为奇数,其他节点度数为偶数,选择这两个节点中较小的节点为起点(起点越小字典序就越小)。
如果每个节点的度数都为偶数,那么选择\(1\)为起点即可。
如果图中节点度数的情况不满足上面两种情况,那么无解。
代码应该也很清楚了:
#include <iostream>
#include <cstdio>
#include <algorithm>
using namespace std;
const int N = 1050;
int n, maxn, vis[N][N], ans[N], s = 1, deg[N];
void euler (int x) {
for (int i = 1; i <= maxn; i ++)
if (vis[x][i]) {
vis[x][i] --;
vis[i][x] --;
euler(i);
}
ans[++ ans[0]] = x;
}
int main () {
scanf("%d", &n);
for (int i = 1; i <= n; i ++) {
int x, y;
scanf("%d%d", &x, &y);
maxn = max(maxn, x);
maxn = max(maxn, y);
vis[x][y] ++;
vis[y][x] ++;
deg[x] ++;
deg[y] ++;
}
for (int i = 1; i <= maxn; i ++)
if (deg[i] & 1) {
s = i;
break;
}
euler(s);
for (int i = ans[0]; i >= 1; i --)
printf("%d\n", ans[i]);
return 0;
}

浙公网安备 33010602011771号