欧拉路

欧拉路

给定一张无向图,若存在一条从节点\(x\)到节点\(y\)的路径,恰好经过每条边一次(节点可以重复经过),那么称这条路径为\(x\)\(y\)的欧拉路。

欧拉回路

如果存在一条欧拉路从\(x\)出发并且回到\(x\),那么称这条路径为欧拉回路。存在欧拉回路的无向图被称为欧拉图。

欧拉路的存在性判定

无向图

  1. 每个节点的度数都是偶数,此时从任意节点出发都存在欧拉回路。

  2. 除了\(x, y\)两个节点度数为奇数,其他节点度数都为偶数,此时存在以\(x, y\)为起点或终点的欧拉路。

有向图

  1. 每个节点的入度都等于出度,此时从任意节点出发都存在欧拉回路。

  2. 除了\(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;
}
posted @ 2022-01-12 19:00  duoluoluo  阅读(317)  评论(0)    收藏  举报