欧拉回路

将所有边全部经过的路径称为欧拉路,起点终点还一样,就可以称为欧拉回路。

判定:

  • 有向图欧拉路:弱连通图中每个点入度 = 出度 或者有一个点入度比出度小一,有一个点入度比出度大一。

  • 有向图欧拉回路:弱连通图中每个点入度 = 出度

  • 无向图欧拉路:联通,且最多有两个点度数为奇数。

  • 无向图欧拉回路:联通,且所有点度数均为偶数。

找方案

找到起点开始 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 FishTwo Trees

模板

UOJ:欧拉回路

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;
}
posted @ 2020-07-12 17:36  JiaZP  阅读(316)  评论(0编辑  收藏  举报