欧拉路径与欧拉回路

创建日期:2025-01-16


欧拉路径和欧拉回路的定义

欧拉路径:

一条经过且不重复经过所有边的路径

欧拉回路:

起点与终点相同的欧拉路径

无向图中的欧拉路径和欧拉回路

充要条件

当度数为奇数的点的个数为2或0时,图中有欧拉路径;当度数为奇数的点的个数恰好为0时,图中有欧拉回路。

证明过程简单,此处不再赘述。

如何找到欧拉路径和欧拉回路

找到欧拉路径,需要借助DFS与栈。先找到度数为奇数的点,以其中一个为起点DFS遍历每条边(每遍历一条边就删掉一条边),在DFS回溯的过程中,将节点添加到栈中,DFS结束后遍历栈并输出即可。

值得注意的是,如果题目要求字典序最小的欧拉路径,则在DFS结束后,应该考虑是否需要将栈反转,也就是使起点编号一定要比终点编号小。

找到欧拉回路的方法与找到欧拉路径的方法相似,但欧拉回路可以以任意一个点作为起点,在要求字典序最小时,应以编号最小的点为起点。

模板代码(邻接矩阵)

void dfs(int u) {
	for (int v = 1; v <= n; v++)
		if (e[u][v]) {
			e[u][v] = e[v][u] = false;
			dfs(v);
		}
	stk[++tot] = u;
}

有向图中的欧拉路径和欧拉回路

充要条件

当恰好有一个出度减入度等于1的点和一个入度减出度等于1的点或入度全部等于出度时,图中有欧拉路径;当入度全部等于出度时,图中有欧拉回路。

如何找到欧拉路径和欧拉回路

与无向图相同,不在赘述。

模板代码(P7771完整代码:邻接表+最小字典序+当前弧优化)

#include <bits/stdc++.h>
using namespace std;

const int MAX_N = 1e5 + 50;
const int MAX_M = 2e5 + 50;
int n, m, now[MAX_N];
vector<int> e[MAX_N];
int indg[MAX_N], outdg[MAX_N];
int stk[MAX_M], tot;

void dfs(int u) {
	while (now[u] < outdg[u]) {
		int v = e[u][now[u]++];
		dfs(v);
	}
	stk[++tot] = u;
}

int main() {
	cin >> n >> m;
	for (int u, v; m--; ) {
		cin >> u >> v;
		e[u].push_back(v);
		indg[v]++, outdg[u]++; 
	}
	for (int i = 1; i <= n; i++)
		sort(e[i].begin(), e[i].end());
		
	int cnt1 = 0, cnt2 = 0;
	for (int i = 1; i <= n; i++) {
		if (indg[i] - outdg[i] == 1) cnt1++;
		else if (indg[i] - outdg[i] == -1) cnt2++;
		else if (indg[i] - outdg[i] != 0) {
			cout << "No";
			return 0;
		} 
	}
	if (!(cnt1 == 1 && cnt2 == 1 || cnt1 == 0 && cnt2 == 0)) {
		cout << "No";
		return 0;
	}
	
	if (cnt1) {
		for (int i = 1; i <= n; i++)
			if (indg[i] - outdg[i] == -1)
				dfs(i); 
	} else
		dfs(1);
		for (int i = tot; i >= 1; i--)
			cout << stk[i] << ' ';	
	return 0;
}

欧拉路径和欧拉回路坑点

1.手写栈一定不能只开 \(n\) 的大小

2.图是否联通,点1不一定存在

3.一定要注意自环,很容易出问题

4.无向图搭配邻接表一定要仔细,防止一条边经过两次

这里给出一种处理无向图邻接表的方法:

struct edge {
	int from, to;
	bool vis;
	int get_v(int u) {
		return u ^ from ^ to;
	}
};

int dg[MAX_N * 2];			// 点的度数 
vector<int> e[MAX_N * 2];	// 每个点连接的边的编号 
edge E[MAX_N];				// 每条边的信息 

void add_edge(int u, int v) {
	E[++cnt] = edge{u, v, false};
	e[u].push_back(cnt);
	e[v].push_back(cnt);
	dg[u]++, dg[v]++;
}

void dfs(int u) {
	vis[u] = true;
	for (; now[u] < e[u].size(); ) {
		int id = e[u][now[u]++];
		if (!E[id].vis) {			// 访问过的边不再访问 
			E[id].vis = true;
			dfs(E[id].get_v(u));
		}
	}
	stk[++top] = u;
}
posted @ 2026-05-19 11:51  xubaichuan  阅读(9)  评论(0)    收藏  举报