欧拉图(欧拉回路与欧拉通路)

在一个图中(有向图或无向图),如果能够从一个结点出发一次性通过所有边且每条边只能通过一次,在通过所有边后能够回到出发点,则该回路称为该图的欧拉回路;不能回到出发点,则该通路称为欧拉通路。含有欧拉回路的图称为欧拉图,含欧拉通路的称为半欧拉图。

最简单的欧拉图:在这里插入图片描述


最简单的半欧拉图:

在这里插入图片描述


如何用算法得到一张有向图的欧拉通路呢(无向图算法类似)?我们来看下面这张图:


在这里插入图片描述
假设1是起点,则有效的欧拉通路是1–>3–>4–>5–>3–>1–>2;看似我们只需要用最普通的DFS算法(DFS图的搜索算法点击这里)就可以实现,但实际上走出一条有效的欧拉通路还是有一定限制的——当我们处于起点位置:结点1时,我们只能选择走结点3而不能选择走结点2,因为结点2是一条死路,不能遍历图的所有边,所以由此可以得出,我们在设计算法寻找欧拉通路时,要注意走到死路的情况。
认真分析欧拉通路的走法我们可以发现,如果一张图是半欧拉图,则这张图最多有一条死路(一条死路是不能到达另一条死路的),而且这条死路一定是最后走的那条路,所以我们可以这样设计算法(找欧拉回路可以也可以用这一算法):

Hierholzer算法——1.从起点出发,进行深度优先搜索,同时维护一个栈。

2.每次沿着某条边从某个顶点移动到另外一个顶点的时候,都需要删除这条边。

3.如果所在结点已经没有可移动的路径,则将所在节点加入到栈中。

4.当所有结点入栈后,将栈弹入结果数组中(倒置),则可以得到这条欧拉通路)

图解:
在这里插入图片描述

Java代码:
这是一道leetcode的题解,用了上文介绍的Hierholzer算法,看题目点击这里

import java.util.*;
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
欧拉回路经过中每条边恰好一次回路欧拉图存在欧拉回路。 对于无向,判断是否是欧拉图可以使用 Fleury 算法。如果该联通且每个点的度数都是偶数,则该欧拉图欧拉回路可以使用 Hierholzer 算法求解。 以下是 C 语言实现无向欧拉回路的代码(假设点编号从0开始): ```c #include <stdio.h> #include <stdlib.h> #define MAXN 1000 int n, m; // n 个点,m 条边 int deg[MAXN]; // 存储每个点的度数 int G[MAXN][MAXN]; // 存储 int ans[MAXN], ans_cnt; // 存储欧拉回路,ans_cnt 表示回路上的点数 void dfs(int u) { for (int v = 0; v < n; v++) { if (G[u][v]) { // 如果存在一条从 u 到 v 的边 G[u][v] = G[v][u] = 0; // 删除该边 dfs(v); } } ans[ans_cnt++] = u; // 将点 u 加入欧拉回路 } int main() { scanf("%d%d", &n, &m); for (int i = 0; i < m; i++) { int u, v; scanf("%d%d", &u, &v); G[u][v] = G[v][u] = 1; // 添加无向边 deg[u]++, deg[v]++; // 维护每个点的度数 } int start = -1; // 找到起点 for (int i = 0; i < n; i++) { if (deg[i] % 2 == 1) { printf("无欧拉回路\n"); return 0; } if (deg[i] > 0 && start == -1) { start = i; } } dfs(start); if (ans_cnt != m+1) { // 如果回路上的点数不等于边数+1,则不存在欧拉回路 printf("无欧拉回路\n"); } else { for (int i = ans_cnt-1; i >= 0; i--) { printf("%d ", ans[i]); } } return 0; } ``` 对于有向,判断是否是欧拉图需要判断每个点的入度和出度是否相等。欧拉回路的求解可以使用 Hierholzer 算法,与无向类似。 以下是 C 语言实现有向欧拉回路的代码(假设点编号从0开始): ```c #include <stdio.h> #include <stdlib.h> #define MAXN 1000 int n, m; // n 个点,m 条边 int indeg[MAXN], outdeg[MAXN]; // 存储每个点的入度和出度 int G[MAXN][MAXN]; // 存储 int ans[MAXN], ans_cnt; // 存储欧拉回路,ans_cnt 表示回路上的点数 void dfs(int u) { for (int v = 0; v < n; v++) { if (G[u][v]) { // 如果存在一条从 u 到 v 的边 G[u][v] = 0; // 删除该边 dfs(v); } } ans[ans_cnt++] = u; // 将点 u 加入欧拉回路 } int main() { scanf("%d%d", &n, &m); for (int i = 0; i < m; i++) { int u, v; scanf("%d%d", &u, &v); G[u][v] = 1; // 添加有向边 outdeg[u]++, indeg[v]++; // 维护每个点的入度和出度 } int start = -1; // 找到起点 for (int i = 0; i < n; i++) { if (indeg[i] != outdeg[i]) { printf("无欧拉回路\n"); return 0; } if (outdeg[i] > 0 && start == -1) { start = i; } } dfs(start); if (ans_cnt != m+1) { // 如果回路上的点数不等于边数+1,则不存在欧拉回路 printf("无欧拉回路\n"); } else { for (int i = ans_cnt-1; i >= 0; i--) { printf("%d ", ans[i]); } } return 0; } ```

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值