15. 위상 정렬
위상 정렬이란?
위상 정렬(Topological Sort)은 **사이클이 없는 방향 그래프(DAG)**에서 노드들을 선후 관계를 지키면서 나열하는 정렬 방법입니다. 보통 작업 순서, 강의 계획, 줄 세우기와 같이 선행 조건이 주어진 문제에서 자주 등장합니다.
특징
- 사이클이 없어야 한다.
- 위상 정렬 결과는 여러 개 존재할 수 있다.
위상 정렬의 원리
- 모든 노드의 진입 차수를 계산한다.
- 진입 차수가 0인 노드를 큐에 삽입한다.
- 큐에서 노드를 꺼내 정렬 결과에 추가하고, 해당 노드에서 나가는 간선을 제거하며 연결된 노드들의 진입 차수를 1씩 감소시킨다.
- 다시 진입 차수가 0이 된 노드를 큐에 넣는다.
- 큐가 빌 때까지 이 과정을 반복한다.
예제: 백준 2252번 “줄 세우기”
문제 설명
- 학생 수
n
명과m
개의 비교 조건이 주어진다. - “A는 B보다 앞에 서야 한다”는 관계가 m개 존재한다.
- 이를 만족하도록 학생들을 나열하는 것이 목적이다.
코드 구현
import sys
# n: 학생 수, m: 비교 데이터
n, m = map(int, sys.stdin.readline().split())
# 인접 리스트
A = []
for i in range(n):
A.append(list())
# 진입 차수 배열 초기화
indegree = [0 for _ in range(n)]
# 간선 정보 입력
for i in range(m):
s, e = map(int, sys.stdin.readline().split())
A[s-1].append(e) # 간선 추가
indegree[e-1] += 1 # 진입 차수 증가
# 큐 초기화 (진입 차수가 0인 노드부터 시작)
queue = []
for i in range(1, n+1):
if indegree[i-1] == 0:
queue.append(i)
# 위상 정렬 수행
while (queue):
now = queue.pop(0)
print(str((now)), end=" ")
for next in A[now - 1]:
indegree[next - 1] -= 1
if (indegree[next - 1] == 0):
queue.append(next)
코드 분석
위상 정렬 정의 및 원리 적용
-
진입 차수 배열 구성:
indegree = [0 for _ in range(n)] for s, e in edges: indegree[e-1] += 1
→ 모든 노드에 대해 몇 개의 노드가 자신에게 연결돼 있는지 카운트합니다.
-
진입 차수 0인 노드 큐에 삽입:
for i in range(1, n+1): if indegree[i-1] == 0: queue.append(i)
-
정렬 배열에 추가하고 연결된 노드 진입 차수 감소:
while queue: now = queue.pop(0) print(now, end=" ") for next in A[now - 1]: indegree[next - 1] -= 1 if indegree[next - 1] == 0: queue.append(next)
→ 선행 관계를 만족시키며 노드를 나열하는 핵심 로직입니다.
정리
항목 | 설명 |
---|---|
문제 유형 | 위상 정렬 (Topological Sort) |
핵심 아이디어 | 진입 차수 배열을 통해 선행 관계를 제거하며 나열 |
주요 자료구조 | 인접 리스트, 큐, 진입 차수 배열 |
시간 복잡도 | O(N + M) (노드 수 + 간선 수) |
위상 정렬은 사이클이 없어야 하며, 정답이 유일하지 않을 수 있습니다. 작업 순서, 강의 수강 순서, 줄 세우기 등 다양한 현실 문제에 응용됩니다.