-
[Algorithm] How To Find Articulation Point with DFS알고리즘 2022. 11. 15. 21:40
DFS Tree의 성질을 이용하여 Articulation Point를 찾기
DFS Tree의 성질과 Articulation Point(단절점)의 정의를 활용하여 Graph에서 Articulation Point(단절점)를 찾아보자.
Definition of Articulation Point
단절점의 정의 : 어떤 Graph G에 속하는 vertex v에 대하여 vertex v와 vertex v와 incident한(edge의 구성요소로 v를 가지고 있는) edge를 G에서 제거했을 때, G가 disconnected 된다면 vertex v는 G의 Articulation Point가 된다,
*Definition of Connected G : G에 속하는 임의의 vertex v, w에 대하여 v에서 w가 reachable 하고 w에서 v가 reachable 하면 G는 connected 하다.
How to Find Articulation Point
> 보조정리1. DFS Tree에서 Root Node의 Child Node의 개수가 2개 이상이면 그 Root Node는 Articulation Point이다. (필요충분조건)
proof
i) -> 방향 증명
--> Contradiction(귀류법). 만약 Root Node가 Articulation Point가 아니라면 Graph G에서 Root Node를 제거한 G가 connected여야 한다. 그러나 DFS Tree에서는 Cycle이 존재하지 않으므로 (by Def of DFS Tree) 모순!ii) <- 방향 증명
--> Contradiction. Child Node의 개수가 1개 이하라면 Root Node를 제거한 Graph G가 Connected이므로 Root Node가 Articulation Point라는 가정에 모순!보조정리2. Non-Root Node인 Graph G에 속하는 임의의 vertex v와 v의 1) Child Node가 u일 때 2) descendant u와 v의 proper Ancestor간 edge가 없으면 v는 Articulation Point. (필요충분조건)
proof
i) -> 방향 증명
Contradiction. v가 Articulation Point가 아니라면, u의 descendant를 포함하는 subtree와 v의 proper Ancestor가 Connected여야하는데 둘 사이에 edge가 없으므로 모순!ii) <- 방향 증명
Contradiction. V가 Articulation Point임에도 불구하고 v의 proper Ancestor와 v의 child node u의 descendant u사이에 edge가 존재하면 v를 뺀 G는 connected이므로 모순!key lemma 3: leaf Node는 Aritculation Point가 될 수 없다.
proof
DFS Tree상에서 leaf Node와 incident한 backEdge가 존재하지 않을 때, leaf Node를 제거하더라도 여전히 남아있는 그래프 G는 Connected하다.
이 세가지 정리를 이용하여 그래프 G에 속하는 Vertex들이 Articulation Point인지 판단해주면 된다.
이것을 의사코드로 나타내면 다음과 같다.
### Pseudo Code #pre[v] : v를 첫 방문한 순서 #low[v] : v의 descendant u(u=v일 수 있음)와 incident한 Back-Edge (u,w)가 존재할 경우 low[v] = min(pre[u], pre[w])로 정의 ArticulationPoint = [False for _ in range(V+1)] counter = 1 #첫 방문 순서와 방문을 완료한 순서를 기록하기 위한 global변수 def DFS(v, parent of v, root Node) visited[v] = True pre[v] = low[v] = counter++ children = 0 for u in graph[v]: if visited[u] and u != parent of v: low[v] = min(low[v], pre[u]) #(v에서 u로의 Back-Edge가 존재할 때) else: DFS(u, v, root Node) low[v] = min(low[v], low[u]) if low[u] >= low[v] and v != Root Node: ArticulationPoint[v] = True children += 1 if v == root Node and children > 1: Articulation[v] = True
연관문제
BOJ 11266 : https://www.acmicpc.net/problem/11266
답안 예시
import sys input = sys.stdin.readline sys.setrecursionlimit(10**6) def explore(graph, v, visited, r, root): global counter children = 0 visited[v] = True pre[v] = counter low[v] = counter counter = counter + 1 for i in graph[v]: if (visited[i]): if (r != i): #BackEdge에 대해서만 low 갱신할 수 있도록 parent의 pre는 배제 low[v] = min(low[v], pre[i]) else: explore(graph, i, visited, v, root) low[v] = min(low[v], low[i]) if (low[i] >= pre[v]): if (v != root): cutPoint[v] = True children += 1 if (r==0 and (children>1)): cutPoint[v] = True V, E = map(int, input().split()) graph = [ [] for i in range(V+1) ] visited = [False for _ in range(V+1)] cutPoint = [False for _ in range(V+1)] pre = [0 for i in range(V+1)] low = [0 for i in range(V+1)] counter = 1 for _ in range(E): a,b = map(int, input().split()) graph[a].append(b) graph[b].append(a) for i in range(1, V+1): root = i explore(graph, i, visited, 0, root) ans = '' cnt = 0 for i in range(1, V+1): if (cutPoint[i] == True): cnt += 1 ans += f'{i} ' print(cnt) if cnt: print(ans)
'알고리즘' 카테고리의 다른 글
[Algorithm] 다이나믹 프로그래밍 (Dynamic Programming) (0) 2022.11.19 [Algorithm] 방해꾼 논법 (Adversary Argument) (0) 2022.11.17 [Algorithm] Upper Bound, Lower Bound와 Optimal Algorithm (0) 2022.11.17 [Algorithm] How To Find SCC in Linear Time Complexity? (0) 2022.11.15 [Algorithm] How to Find Binconnected Component by using Articulation Point (0) 2022.11.15