Source code for titan_pylib.graph.get_articulation_points
1from types import GeneratorType
2
3"""Return articulation points. / O(|V|+|E|)"""
4
5
6# https://algo-logic.info/articulation-points/
[docs]
7def get_articulation_points(G: list[list[int]]) -> list[int]:
8 n = len(G)
9 order = [-1] * n
10 res: list[int] = []
11 cnt = 0
12
13 def antirec(func):
14 # 再帰用デコレータ
15 # yieldにするのを忘れないこと
16 # 参考: https://github.com/cheran-senthil/PyRival/blob/master/pyrival/misc/bootstrap.py
17 stack = []
18
19 def wrappedfunc(*args, **kwargs):
20 if stack:
21 return func(*args, **kwargs)
22 to = func(*args, **kwargs)
23 while True:
24 if isinstance(to, GeneratorType):
25 stack.append(to)
26 to = next(to)
27 else:
28 stack.pop()
29 if not stack:
30 break
31 to = stack[-1].send(to)
32 return to
33
34 return wrappedfunc
35
36 @antirec
37 def dfs(v: int, p: int) -> int:
38 nonlocal cnt
39 r_min = order[v] = cnt
40 fcnt = 0
41 p_art = 0
42 cnt += 1
43 for w in G[v]:
44 if w == p:
45 continue
46 if order[w] == -1:
47 ret = yield dfs(w, v)
48 p_art |= order[v] <= ret
49 r_min = min(r_min, ret)
50 fcnt += 1
51 else:
52 r_min = min(r_min, order[w])
53 p_art |= r_min == order[v] and len(G[v]) > 1
54 if (p == -1 and fcnt > 1) or (p != -1 and p_art):
55 res.append(v)
56 yield r_min
57
58 if G:
59 dfs(0, -1)
60 return res