📜  无向图中的欧拉路径(1)

📅  最后修改于: 2023-12-03 15:40:06.430000             🧑  作者: Mango

无向图中的欧拉路径

什么是欧拉路径?

在图论中,欧拉路径又称欧拉通路,是指经过图中每条边恰好一次的路径。如果该路径的起点和终点重合,则称其为欧拉回路或欧拉环。

什么样的无向图存在欧拉路径?欧拉回路?

无向图中存在欧拉路径的条件是:每个顶点的度数为偶数或者恰有两个顶点的度数为奇数。

无向图中存在欧拉回路的条件是:每个顶点的度数均为偶数。

如何寻找欧拉路径?
Fleury算法

Fleury算法是寻找欧拉路径的一种贪心算法。

步骤:

  1. 任选一个顶点作为起点。
  2. 如果当前顶点有未被访问的边,则选择一条未被访问的边,沿该边移动到下一个未被访问的顶点,并将当前走过的边标记为已访问过。
  3. 如果当前顶点没有未被访问的边,则后退到上一个顶点,重复步骤2。
  4. 当程序结束时,已访问的边即为欧拉路径。

需要注意的是,如果存在多个欧拉路径,Fleury算法只能找到其中一条。

Hierholzer算法

Hierholzer算法是寻找欧拉路径和欧拉回路的一种算法。

步骤:

  1. 任选一个顶点作为起点。
  2. 沿着任何一条未被访问的边前进,直到无法继续前进。
  3. 此时一定到达了一个环,开始沿着该环找到所有未访问过的边,并加入欧拉路径中,同时标记这些边为已访问。
  4. 如果存在未访问的边,那么从路径中的一个顶点开始重复步骤2。
  5. 当程序结束时,已访问的边即为欧拉路径或欧拉回路。

需要注意的是,如果存在多个欧拉路径或欧拉回路,Hierholzer算法能够找到其中所有的欧拉路径或欧拉回路。

示例代码
# Fleury算法(Python版)

def dfs(u):
    global path
    for v in graph[u]:
        if not visited[edge_dict[(u,v)]]:
            visited[edge_dict[(u,v)]] = True
            path.append((u,v))
            dfs(v)
            break

n,m = map(int,input().split())
graph = [[] for _ in range(n)]
degree = [0] * n
for i in range(m):
    u,v = map(int,input().split())
    graph[u-1].append(v-1)
    graph[v-1].append(u-1)
    degree[u-1] += 1
    degree[v-1] += 1

start = -1
for i in range(n):
    if degree[i] % 2 == 1:
        start = i
        break

if start == -1:
    start = 0

path = []
visited = [False] * m
edge_dict = {}
for i in range(m):
    u,v = sorted(map(int,input().split())))
    edge_dict[(u-1,v-1)] = i  

visited = [False] * m
dfs(start)

print([u+1 for u,v in path])
# Hierholzer算法(Python版)

def find_euler_path():
    stack = [(start_node,-1)]
    path = []
    while stack:
        u,e = stack[-1]
        if len(graph[u]) == 0:
            path.append(e)
            stack.pop()
        else:
            v = graph[u].pop()
            if visited[edge_dict[(u,v)]]:
                continue
            visited[edge_dict[(u,v)]] = True
            stack.append((v,edge_dict[(u,v)]))
    return path[::-1]

n,m = map(int,input().split())
graph = [[] for _ in range(n)]
degree = [0] * n
for i in range(m):
    u,v = map(int,input().split())
    graph[u-1].append(v-1)
    graph[v-1].append(u-1)
    degree[u-1] += 1
    degree[v-1] += 1

start = -1
for i in range(n):
    if degree[i] % 2 == 1:
        start = i
        break
if start == -1:
    start = 0

edge_dict = {}
visited = [False] * m
for i in range(m):
    u,v = sorted(map(int,input().split())))
    edge_dict[(u-1,v-1)] = i      

print([u+1 for u in find_euler_path()])