Scc
SCC
Topological Sort 등을 비롯한 많은 Directed Graph 에 대한 알고리즘은 DAG(Directed Acyclic Graph) 를 요구한다. 그래서 Graph 의 정보를 유지하면서 Cycle 을 제거할 필요성이 생겼고, 이를 위한 알고리즘이 SCC 이다.
A directed graph is called strongly connected if there is a path in each direction between each pair of vertices of the graph
A strongly connected component of a directed graph G is a subgraph that is strongly connected, and is maximal with this property: no additional edges or vertices from G can be included in the subgraph without breaking its property of being strongly connected.
위키의 위 두 문장이 SCC 를 정의한다. 즉 Directed Graph 의 Strongly Connected Subgraph 중 더이상 Vertex 를 추가할 수 없는 것들이다.
Graph 의 SCC 를 하나의 Vertex 로 치환하는 것을 Graph Condensation 이라고 하며 그 결과는 여러 유용한 특징을 갖는다.
- DAG(Directed Acyclic Graph) 를 만족한다. 이에 대한 증명은 DAG 가 아닐 시 SCC 가 그 속성을 유지하면서 Vertex 를 넣을 수 없음과 모순된다는 걸 이용하면 쉽게 증명할 수 있다.
- Edges 의 방향을 바꾸면 Edge 의 방향만 다른 결과를 낳는다. Edges 의 방향이 반대로 되어도 SCC 의 구성이 바뀌지 않기 때문이다.
SCC 를 이용해 여러 문제를 풀 수 있고, 이를 구하는 방법도 여러가지가 있다.
여기선 DFS 를 이용해 O(\(\vert V \vert + \vert E \ vert\)) 내에 구하는 두가지 유명 알고리즘만 정리한다. 아래 코드는 BOJ 문제 의 풀이코드이다.
Kosaruju Algorithm
코드
설명
DFS 를 두번 돌린다.
- 첫번째 DFS 는 Node 방문이 끝났을 때의 시점을 기록한다. 역방향이 필요하므로 Stack 을 이용해 이를 구현한다.
- 두번째 DFS 는 역간선을 이용해 가장 나중에 끝난 Node 부터 탐색한다. 이때 방문하는 Node 들은 하나의 SCC 에 소속된다.
증명은 간단하다. SCC 인 A
, B
가 있어서 A
의 Node 부터 DFS 를 한다고 하자.
A
와B
는 SCC 의 정의 상 양방향으로 연결되지 않는다.A
에서B
로 연결된 간선이 존재한다고 하자. DFS 는A
를 걸쳐서B
로 갈 수 밖에 없으므로B
의 탐색이 종료되고A
가 종료된다. 이 때 역방향 간선 중에는A
에서B
로 연결된 간선이 전제 상 없다. 그럼 두번째 DFS 에서A
를 먼저 탐색하고 이때B
를 방문하지 않음이 보장된다.B
에서A
로 연결된 간선이 존재한다고 하자. 그러면A
를 탐색 후B
를 탐색하므로 두번째 DFS 에선B
를 먼저 탐색하게 된다. 전제 상 역간선 중에는B
부터A
로 연결된 간선이 존재하지 않는다. 그러므로 두번째 DFS 에서B
를 탐색 시A
를 방문하지 않음이 보장된다.A
와B
사이에 아무 간선이 없는 경우 별개의 Graph 라고 생각하고 각각 수행한 후 합치면 되므로 논외.
정의 상 SCC 내부에선 역간선을 이용해 탐색해도 모든 Node 를 방문한다. 그러므로 두번째 DFS 에서 이미 방문한 Node 를 재방문하지 않는다면 SCC 를 구할 수 있다. 증명 끝.
특징
두번째 DFS 의 방문 순서대로 위상정렬이 되어있다는 특징이 있다.
Tarjan Algorithm
코드
설명
Tarjan Algorithm 은 SCC 의 어떠한 Node 도 그것을 Root 로 한 Spanning Tree 가 SCC 를 포함한다는 사실을 이용한다. 이는 Spanning Tree 를 이용하기 때문에 Articulation(단절점) 알고리즘과 흡사하다.
SCC 를 Vertex 하나로 대체한 Graph 가 DAG 이고 DAG 에는 하나 이상의 Leaf Node 가 있다. Leaf Node 에 해당되는 SCC 에서는 그 안에서 밖으로 나가는 Edge 가 존재하지 않는다. 그러므로 Spanning Tree 를 만들었을 때 하나의 SCC 만을 포함하는 Subtree 는 하나 이상 존재한다.
이러한 Subtree 를 찾았다고 해보자. 그러면 이 Subtree 와 나머지 Graph 를 잇는 Edge 를 모두 끊어버릴 수 있다. Subtree 가 빠진 Graph 는 Empty Graph 가 아닌 한 Graph Condensation 시 하나 이상의 Leaf Node 가 새로 생김이 보장된다. 위를 반복하자. 그러면 Graph 내의 SCC 를 모두 구할 수 있다.
그러면 오직 하나의 SCC 만을 포함하는 Subtree(편의상 A
)를 어떻게 구할까?
우선 DFS 를 이용해 Spanning Tree 를 만들 때 Node 마다 방문시각을 기록한다. 그러면 A
는 자신을 경유해 Graph 상에서(Spanning Tree 의 Edge 만 사용하는게 아니다.) 도달 가능한 Node 중에 가장 빠른 방문시각을 갖는 Node 를 Root 로 하는 Tree 이다. SCC 내에서는 어디를 시작점으로 잡든 모든 점에 도달할 수 있고, A
는 온전히 SCC 의 Node 만을 가지기 때문에 성립한다.
특징
DFS 의 특성 상 roots[]
의 숫자의 역순으로 SCC 가 위상정렬 되어 있다.
댓글남기기