基础概念

前提:连通图
无向图:
欧拉通路:存在欧拉通路的充要条件是度数为奇数的点只能有0或2个
欧拉回路:存在欧拉回路的充要条件是度数为奇数的点只能有0个

有向图:
欧拉通路:存在欧拉通路的充要条件是要么所有点的入度等于出度,要么除了两个点之外,其余所有点的出度等于入度,剩余的两个点一个满足入度比出度大一,另一个满足出度比入度大一。
欧拉回路:存在欧拉回路的充要条件是所有节点的出度均等于入度。

代码实现:

  1. // 不做优化的处理方式
  2. // 边
  3. dfs(u) {
  4. for (v : edge[u]) {
  5. if (used[v]) continue; // 针对无向图才有
  6. dfs(v);
  7. q[++tt] = v;
  8. }
  9. }
  10. // 点
  11. dfs(u) {
  12. for (v : edge[u]) {
  13. if (used[v]) continue; // 针对无向图才有
  14. dfs(v);
  15. }
  16. q[++tt] = u;
  17. }

模板

  1. 记录欧陆通路/欧拉回路经过的边

本质是记录最后一条被遍历的边
AcWing 1184. 欧拉回路
如果不做优化,最坏时间复杂度为O(m2)
优化的做法是边dfs边删除边,防止再次遍历到该点时所有出边又被遍历一次。

  1. import java.util.*;
  2. import java.io.*;
  3. public class Main {
  4. static final int N = 100010, M = 400010;
  5. static int[] h = new int[N], e = new int[M], ne = new int[M];
  6. static int[] res = new int[M];
  7. static int idx, cnt;
  8. static int type, n, m;
  9. static boolean[] used = new boolean[M];
  10. static int[] din = new int[N], dout = new int[N];
  11. public static void main(String[] args) throws IOException {
  12. var sc = new Scanner(); // 换成Fast IO
  13. type = sc.nextInt();
  14. n = sc.nextInt();
  15. m = sc.nextInt();
  16. Arrays.fill(h, -1);
  17. for (int i = 0; i < m; i++) {
  18. int a = sc.nextInt(), b = sc.nextInt();
  19. add(a, b);
  20. if (type == 1) add(b, a);
  21. din[b]++;
  22. dout[a]++;
  23. }
  24. if (type == 1) {
  25. for (int i = 1; i <= n; i++) {
  26. if ((din[i] + dout[i]) % 2 == 1) {
  27. System.out.println("NO");
  28. return;
  29. }
  30. }
  31. } else {
  32. for (int i = 1; i <= n; i++) {
  33. if (din[i] != dout[i]) {
  34. System.out.println("NO");
  35. return;
  36. }
  37. }
  38. }
  39. for (int i = 1; i <= n; i++) {
  40. if (h[i] != -1) {
  41. dfs(i);
  42. break;
  43. }
  44. }
  45. if (cnt != m) {
  46. System.out.println("NO");
  47. return;
  48. }
  49. System.out.println("YES");
  50. for (int i = m; i > 0; i--)
  51. System.out.print(res[i] + " ");
  52. System.out.println();
  53. }
  54. static void dfs(int u) {
  55. while (h[u] != -1) {
  56. int i = h[u];
  57. if (used[i]) {
  58. h[u] = ne[i];
  59. continue;
  60. }
  61. used[i] = true;
  62. if (type == 1) used[i ^ 1] = true;
  63. h[u] = ne[i];
  64. int t;
  65. if (type == 1) {
  66. t = i / 2 + 1;
  67. if (i % 2 == 1) t = -t;
  68. } else t = i + 1;
  69. dfs(e[i]);
  70. res[++cnt] = t;
  71. }
  72. }
  73. static void add(int a, int b) {
  74. e[idx] = b;
  75. ne[idx] = h[a];
  76. h[a] = idx++;
  77. }
  78. }
  1. 记录欧拉通路/欧拉回路经过的点

本质是记录最后一个被遍历的点
AcWing 1124. 骑马修栅栏
求欧拉回路/欧拉通路的最小字典序路径上的点
直接暴力做就行,不需要删边优化

  1. import java.util.*;
  2. public class Main {
  3. static final int N = 510, M = 1500;
  4. static int[][] g = new int[N][N];
  5. static int n, m;
  6. static int cnt;
  7. static int[] res = new int[M];
  8. static int[] din = new int[N], dout = new int[N];
  9. public static void main(String[] args) {
  10. Scanner sc = new Scanner(System.in);
  11. m = sc.nextInt();
  12. int min = N;
  13. for (int i = 1; i <= m; i++) {
  14. int a = sc.nextInt(), b = sc.nextInt();
  15. g[a][b]++;
  16. g[b][a]++;
  17. min = Math.min(min, a);
  18. min = Math.min(min, b);
  19. din[b]++;
  20. dout[a]++;
  21. }
  22. for (int i = 1; i < N; i++) {
  23. if ((din[i] + dout[i]) % 2 == 1) {
  24. min = i;
  25. break;
  26. }
  27. }
  28. dfs(min);
  29. for (int i = cnt; i > 0; i--)
  30. System.out.println(res[i]);
  31. }
  32. static void dfs(int u) {
  33. for (int i = 1; i < N; i++) {
  34. if (g[u][i] > 0) {
  35. g[u][i]--;
  36. g[i][u]--;
  37. dfs(i);
  38. }
  39. }
  40. res[++cnt] = u;
  41. }
  42. }

应用

AcWing 1123. 铲雪车
欧拉回路,脑筋急转弯题目 + 数学
AcWing 1185. 单词游戏
判断图是否为欧拉回路或欧拉通路