-
Notifications
You must be signed in to change notification settings - Fork 32
/
Copy pathgetEulerPath.py
83 lines (71 loc) · 2.5 KB
/
getEulerPath.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
# 无向图存在欧拉路径<=> 度数为奇数的点只能有 0 或 2 个,不存在出度入度之说
# 有向图存在欧拉路径<=> 出度减入度不为 0 的点只能有 0 或 2 个,且 2 个时`起点出度比入度多 1,终点入度比出度多 1`
from collections import defaultdict
from typing import DefaultDict, List, Set, Tuple
def getEulerPath(
allVertex: Set[int], adjMap: DefaultDict[int, Set[int]], *, isDirected: bool
) -> Tuple[bool, List[int]]:
"""求欧拉路径,需要寻找出发点,保证输入的图是连通图"""
if not adjMap:
return False, []
start = next(iter(adjMap))
if isDirected:
indegree, outdegree = {v: 0 for v in allVertex}, {v: 0 for v in allVertex}
minusOne, one = 0, 0
for cur, nexts in adjMap.items():
outdegree[cur] += len(nexts)
for next_ in nexts:
indegree[next_] += 1
for cur in allVertex:
diff = outdegree[cur] - indegree[cur]
if diff == 0:
if outdegree[cur] == 0:
return False, [] # 入度为 0,出度也为 0,不是联通图
elif diff == 1:
start = cur
one += 1
elif diff == -1:
minusOne += 1
else:
return False, []
if (minusOne, one) not in ((1, 1), (0, 0)):
return False, []
else:
oddCount = 0
for cur in allVertex:
degree = len(adjMap[cur])
if degree == 0:
return False, [] # 度数为 0,不是联通图
elif degree & 1:
oddCount += 1
start = cur
if oddCount not in (0, 2):
return False, []
res = []
stack = [start]
cur = start
while stack:
if adjMap[cur]:
stack.append(cur)
next_ = adjMap[cur].pop()
if not isDirected:
adjMap[next_].remove(cur) # 无向图 要删两条边
cur = next_
else:
res.append(cur)
cur = stack.pop()
return True, res[::-1]
if __name__ == "__main__":
E = [
(2, 0),
(0, 3),
(0, 1),
(3, 2),
(1, 2),
]
allVertex = {0, 1, 2, 3}
adjMap = defaultdict(set)
for a, b in E:
adjMap[a].add(b)
adjMap[b].add(a)
print(getEulerPath(allVertex, adjMap, isDirected=False))