欧拉路径-欧拉回路

概念:
欧拉路径:经过图中所有的边一次(一笔画)是欧拉路径
欧拉回路:经过图中所有的边一次,并回到起点,是欧拉回路。
欧拉图:存在欧拉回路的图就是欧拉图
欧拉回路是欧拉路径,欧拉路径不一定是欧拉回路。
半欧拉图:只有欧拉路径(非回路)的图是半欧拉图。

判断一个无向图和有向图是否有欧拉路径和欧拉回路很简单,无向图看每个点的度数,有向图看每个点的出入度。

欧拉路径 欧拉回路
无向图 奇度数结点数为 0 或 2 奇度数结点数为 0
有向图 起点的入度 - 出度 = -1,终点的入度 - 出度 = 1, 其余点入度=出度 每个结点的入度 = 出度

无向图中,如果奇度数点个数为2,可以直接看出该图是半欧拉图,有一个非回路的欧拉路径。而且以这两个点为起终点。

推荐一个不错的教程,来自油管的 WilliamFiset
Existence of Eulerian Paths and Circuits | Graph Theory
在这里插入图片描述

另一个有关欧拉路径回路的问题是找出欧拉路径回路。用深搜dfs就可以很容易的找出来了。
具体的说是 Hierholzer’s Algorithm —Hierholzer算法

具体思路有点像dfs版拓扑排序。这个算法前提是图已经是判断出来是有欧拉路径或欧拉图了,然后还要找到开始结点。无向图中,没有奇数点就随便找起点,有两个奇数点,这两个点就是起终点,可以随便选取一个做起点。有向图中,所有点出入度都相同就任意取起点,如果有一个入度-出度=-1的点,这个点就是起点,而且还有一个入度-出度=1的为终点。

起点找完,开始深搜,

  1. 每搜一条边,要标记为走过,
  2. 遇到阻塞(该结点没有后续邻边或该结点的邻边都搜完),该节点入栈,
  3. 回溯,继续搜可以走的边,遇到阻塞一样要入栈。
  4. 直到深搜结束,得到一个序列存在栈中
    因为每次都是阻塞了才入栈,说明每次入栈的点都是最靠后的,栈中的序列是倒序的。最后弹出元素得到的序列就是顺序的路径。

存图数据可以用邻接矩阵,也可以用邻接表,这里我用了邻接矩阵,写起来很方便,还可以用作标记数组,标记边的访问情况。

油管中的视频有动态的演示,推荐大家去看一看,逼站也有对应的翻译的视频
Eulerian Path Algorithm | Graph Theory

dfs求欧拉回路的方法大致如下:
伪代码:

fun dfs(u):
	for (v, v < n, v++):
		if (graph[u][v]):
			graph[u][v] = graph[v][u] = 0
			dfs(u)
	stack.put(u)

main:
	# graph[u][v] == 1 表示u-->v有边,0表示没边,如果有重边就可以在原来的基础上加1
	stack, graph[n][n] 
	if (has_euler_path()):
		start = find_start()
		dfs(start)
		while (!stack.empty)
			print(stack.pop())
	else:
		print("The graph do not exist Euler Path.")
	
	

由于dfs容易爆栈,这里用python写了个非递归的,用栈模拟递归的方法。从当前结点开始搜,搜到一个可以访问的结点就入栈,去边,break,继续上一层循环,直到遇到阻塞就出栈,把出栈的结点压入路径的栈中。

def get_path(st):
    """Hierholzer算法(非递归)"""
    path = []
    stack = [st]
    while stack:
        curnode = stack[-1]
        for v in range(n):
            if graph2[curnode][v]:
                graph2[curnode][v
  • 2
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值