방향있는 그래프(directed graph)
Last updated
Last updated
방향이 있는 그래프에는 정점 v
에서 정점 u
으로 이동이 가능하지만 u
에서는 v
로 이동할 수 없는 간선이 있다. 따라서 어떤 정점에서 다른 정점으로 이동하기 위한 선형 순서(linear order)가 그래프에 존재할 수 있다.
위 그래프의 경우 정점 4
에 도착하기 위해서는 정점 2
를 거쳐야 하고, 정점 2
를 거치려면 정점 1
에서 출발해야 한다. 1 -> 2 -> 4
와 같이 경로에 정점의 순서가 선형적으로 있는 것이다.
순환 그래프는 아래와 같은 형태를 한다.
모든 정점 또는 일부가 하나의 사이클을 이루는 그래프를 순환그래프(cycled graph)라고 한다. 위 그래프의 경우 A -> B -> C -> E -> D -> B -> C ...
와 같이 정점 B, C, E, D가 사이클을 이루고 있다. 어느 정점이 다른 정점에 우선하는지 순서를 결정할 수 없기 때문에 순환그래프에는 선형적 순서가 존재하지 않는다.
DAG(Directed Acyclic Graph)는 두 정점 사이의 간선에 방향이 있으며 그래프 내 사이클이 존재하지 않는 그래프다. DAG에는 선형적 순서가 존재한다.
방향있는 그래프에서 SCC이란 정점 v
에서 정점 u
로 향하는 경로가 있으면서 u
에서 v
로 향하는 경로도 있는 서브그래프를 뜻한다.
위 그래프에는 SCC 총 5개다.
정점 D
, G
, F
는 self-loop 경로가 있어서 SCC에 포함된다.
정점 H
에서 I
로 이동가능한 경로가 있고 I
에서도 H
로 향하는 경로가 있으므로 H
, I
는 SCC에 포함된다.
정점 A
, B
, C
, E
에도 두 정점에서 서로 이동가능한 경로가 모두 존재한다. (A
에서 C
로 가는 경로가 있으면서 C
에서 A
로 가는 경로가 존재한다.)
이러한 SCC들을 뭉뚱그려서 하나의 정점으로 표현할 수 있는데, 이렇게 표현된 그래프를 메타그래프(metagraph)라고 한다. 위 SCC들을 메타그래프로 나타내면 아래와 같다.
정점 D
에서 정점 A
로 향하는 경로가 있고 정점 A
의 connected component는 B
, C
, E
이다. 따라서 D
에서 B
, C
, E
로 향하는 경로도 있다.
이 때 메타그래프는 항상 DAG(Directed Acyclic Graph)형태를 하고 있다. 그래프 내에서 SCC는 항상 사이클을 이루고, 사이클을 이루는 이 connected component들은 메타그래프에서 항상 하나의 정점으로 추상화되기 때문이다.
DAG를 정렬하는 방법은 아래와 같았다.
그래프에서 싱크를 찾는다.
찾은 싱크를 결과리스트에 삽입한다.
싱크와 간선을 그래프에서 삭제한다.
1 ~ 3을 반복한다.
그래프에서도 SCC들을 탐색하기 위해서는 sink SCC를 찾아야 한다.
그래프 G
의 간선 방향을 모두 역으로 바꾼다. 간선방향을 바꾼 그래프를 rG
라고 하자. G
와 rG
의 SCC는 동일하다.
rG
에서 DFS를 실행하여 각 정점들의 post time(어떤 정점 v
에서 호출한 서브루틴들이 완전히 종료되어 v
를 파라미터로 갖는 함수가 완전히 종료되는 시간)을 내림차순 정렬한다. rG
에서 post time이 가장 높은 정점은 rG
의 source이면서 G
의 sink에 해당한다.
post time이 가장 큰 정점을 v
라고 하자. v
를 시작으로 DFS를 실행한다. DFS를 통해 찾아낸 정점들은 v
의 connected component들이며 G
의 sink SCC이다.
v
와 v
의 connected component들을 G에서 삭제한다.
v
다음으로 post time이 큰 정점을 시작으로 DFS를 실행한다.
반복
위 그래프에서 정점 내 숫자는 각 정점들의 post time을 나타낸다. post time이 가장높은 18에 해당하는 정점 F
에서 DFS를 실행했을 때 F
에서 이동가능한 경로가 없으므로 F
가 sink SCC이다. F
를 그래프에서 삭제한다.
F
다음으로 post time이 17인 정점 I
에서 DFS를 실행했을 때 H
로 이동가능하며 H
에서도 I
로 이동가능하다. H
와 I
가 하나의 sink SCC이므로 H
와 I
를 그래프에서 삭제한다.
아래 코드는 그래프에서 그래프 내 SCC의 갯수를 구하는 distinguish_scc()
를 구현한 것이다. reverse_adjacent_list
는 방향을 역으로 바꾼 간선들을 나타낸다.
DFS의 시간복잡도는 O(|V| + |E|)
이다. distinguish_scc()
는 그래프 G
에서 DFS를 1번 실행하고 간선의 방향을 바꾼 rG
에서 DFS를 1번 실행한다. post_time
을 기준으로 정렬된 각 정점들을 가지고 DFS를 또 실행하기 때문에 시간 복잡도는 O(3 * (|V| + |E|))
= O(|V| + |E|)
다.
출처