基础概念
前提:连通图
无向图:
欧拉通路:存在欧拉通路的充要条件是度数为奇数的点只能有0或2个
欧拉回路:存在欧拉回路的充要条件是度数为奇数的点只能有0个
有向图:
欧拉通路:存在欧拉通路的充要条件是要么所有点的入度等于出度,要么除了两个点之外,其余所有点的出度等于入度,剩余的两个点一个满足入度比出度大一,另一个满足出度比入度大一。
欧拉回路:存在欧拉回路的充要条件是所有节点的出度均等于入度。
代码实现:
// 不做优化的处理方式
// 边
dfs(u) {
for (v : edge[u]) {
if (used[v]) continue; // 针对无向图才有
dfs(v);
q[++tt] = v;
}
}
// 点
dfs(u) {
for (v : edge[u]) {
if (used[v]) continue; // 针对无向图才有
dfs(v);
}
q[++tt] = u;
}
模板
- 记录欧陆通路/欧拉回路经过的边
本质是记录最后一条被遍历的边
AcWing 1184. 欧拉回路
如果不做优化,最坏时间复杂度为O(m2)
优化的做法是边dfs边删除边,防止再次遍历到该点时所有出边又被遍历一次。
import java.util.*;
import java.io.*;
public class Main {
static final int N = 100010, M = 400010;
static int[] h = new int[N], e = new int[M], ne = new int[M];
static int[] res = new int[M];
static int idx, cnt;
static int type, n, m;
static boolean[] used = new boolean[M];
static int[] din = new int[N], dout = new int[N];
public static void main(String[] args) throws IOException {
var sc = new Scanner(); // 换成Fast IO
type = sc.nextInt();
n = sc.nextInt();
m = sc.nextInt();
Arrays.fill(h, -1);
for (int i = 0; i < m; i++) {
int a = sc.nextInt(), b = sc.nextInt();
add(a, b);
if (type == 1) add(b, a);
din[b]++;
dout[a]++;
}
if (type == 1) {
for (int i = 1; i <= n; i++) {
if ((din[i] + dout[i]) % 2 == 1) {
System.out.println("NO");
return;
}
}
} else {
for (int i = 1; i <= n; i++) {
if (din[i] != dout[i]) {
System.out.println("NO");
return;
}
}
}
for (int i = 1; i <= n; i++) {
if (h[i] != -1) {
dfs(i);
break;
}
}
if (cnt != m) {
System.out.println("NO");
return;
}
System.out.println("YES");
for (int i = m; i > 0; i--)
System.out.print(res[i] + " ");
System.out.println();
}
static void dfs(int u) {
while (h[u] != -1) {
int i = h[u];
if (used[i]) {
h[u] = ne[i];
continue;
}
used[i] = true;
if (type == 1) used[i ^ 1] = true;
h[u] = ne[i];
int t;
if (type == 1) {
t = i / 2 + 1;
if (i % 2 == 1) t = -t;
} else t = i + 1;
dfs(e[i]);
res[++cnt] = t;
}
}
static void add(int a, int b) {
e[idx] = b;
ne[idx] = h[a];
h[a] = idx++;
}
}
- 记录欧拉通路/欧拉回路经过的点
本质是记录最后一个被遍历的点
AcWing 1124. 骑马修栅栏
求欧拉回路/欧拉通路的最小字典序路径上的点
直接暴力做就行,不需要删边优化
import java.util.*;
public class Main {
static final int N = 510, M = 1500;
static int[][] g = new int[N][N];
static int n, m;
static int cnt;
static int[] res = new int[M];
static int[] din = new int[N], dout = new int[N];
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
m = sc.nextInt();
int min = N;
for (int i = 1; i <= m; i++) {
int a = sc.nextInt(), b = sc.nextInt();
g[a][b]++;
g[b][a]++;
min = Math.min(min, a);
min = Math.min(min, b);
din[b]++;
dout[a]++;
}
for (int i = 1; i < N; i++) {
if ((din[i] + dout[i]) % 2 == 1) {
min = i;
break;
}
}
dfs(min);
for (int i = cnt; i > 0; i--)
System.out.println(res[i]);
}
static void dfs(int u) {
for (int i = 1; i < N; i++) {
if (g[u][i] > 0) {
g[u][i]--;
g[i][u]--;
dfs(i);
}
}
res[++cnt] = u;
}
}
应用
AcWing 1123. 铲雪车
欧拉回路,脑筋急转弯题目 + 数学
AcWing 1185. 单词游戏
判断图是否为欧拉回路或欧拉通路