위상 정렬이란, 사이클이 없는 방향 그래프(DAG)를 방향성에 거스르지 않도록 순서대로 나열하는 것입니다. 대표적인 예시로, 선수 과목을 고려해서 학습 순서를 설정하는 것이 있습니다. 일반화학, 유기화학1, 유기화학2 라는 3과목이 있을 때, 아래의 학습 순서들 중 적절한 순서는 (2)가 될 것입니다. (1) 일반화학 -> 유기화학2 -> 유기화학1 (2) 일반화학 -> 유기화학1 -> 유기화학2
우선, 비순환 방향 그래프(DAG)에 대해 정리하겠습니다.
비순환 방향 그래프 (Directed Acyclic Graph)
위와 같이 방향 그래프이면서 사이클이 없는 그래프를 DAG라고 한다.
DAG와 Topological sort 위상 정렬은 이러한 비순환 방향 그래프에서 정점들을 선형으로 정렬하는 것이다. 모든 간선 (u,v)에 대해 정점 u가 정점 v보다 먼저 오는 순서로 정렬되는 것이다, 이때, 위상 정렬의 결과는 반드시 하나가 아닐 수도 있다. 이는 후에 설명하도록 하겠다.
정렬 결과를 그림으로 표현하면 아래와 같다. 진입차수와 진출차수 진입차수: 특정한 정점으로 들어오는 간선의 개수 진출차수: 특정한 정점에서 나가는 간선의 개수
from collections import deque
# 노드의 개수와 간선의 개수를 입력 받기
v, e = map(int, input().split())
# 모든 노드에 대한 진입차수는 0으로 초기화
indegree = [0] * (v + 1)
# 각 노드에 연결된 간선 정보를 담기 위한 연결 리스트 초기화
graph = [[] for i inrange(v + 1)]
# 방향 그래프의 모든 간선 정보를 입력 받기for _ inrange(e):
a, b = map(int, input().split())
graph[a].append(b) # 정점 A에서 B로 이동 가능# 진입 차수를 1 증가
indegree[b] += 1# 위상 정렬 함수deftopology_sort():
result = [] # 알고리즘 수행 결과를 담을 리스트
q = deque() # 큐 기능을 위한 deque 라이브러리 사용# 처음 시작할 때는 진입차수가 0인 노드를 큐에 삽입for i inrange(1, v + 1):
if indegree[i] == 0:
q.append(i)
# 큐가 빌 때까지 반복while q:
# 큐에서 원소 꺼내기
now = q.popleft()
result.append(now)
# 해당 원소와 연결된 노드들의 진입차수에서 1 빼기for i in graph[now]:
indegree[i] -= 1# 새롭게 진입차수가 0이 되는 노드를 큐에 삽입if indegree[i] == 0:
q.append(i)
# 위상 정렬을 수행한 결과 출력for i in result:
print(i, end=' ')
topology_sort()