欧拉路径与欧拉回路
创建日期: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;
}

浙公网安备 33010602011771号