[위상 정렬의 핵심 이론]
1. 진입 차수는 자기 자신을 가리키는 에지의 개수이다. 인접 리스트에 기반을 두어 진입 차수 리스트에 D[N]++ 한다.
2. 진입 차수 리스트에서 진입 차수가 0인 노드를 선택하고, 선택된 노드를 정렬 리스트에 저장한다. 그 후, 인접 리스트에서 선택된 노드가 가리키는 노드들의 진입 차수를 1씩 뺀다. 이 과정을 모든 노드가 정렬될 때까지 반복한다.
시간 제한 2초, 골드 III, 백준 2252번
N명의 학생들을 키 순서대로 줄을 세우려고 한다. 각 학생의 키를 직접 재서 정렬하면 간단하겠지만, 마땅한 방법이 없어서 두 학생의 키를 비교하는 방법을 사용하기로 하였다. 그나마도 모든 학생들을 다 비교해 본 것이 아니고, 일부 학생들의 키만을 비교해 보았다.
일부 학생들의 키를 비교한 결과가 주어졌을 때, 줄을 세우는 프로그램을 작성하시오.
첫째 줄에 N(1 ≤ N ≤ 32,000), M(1 ≤ M ≤ 100,000)이 주어진다. M은 키를 비교한 회수이다. 다음 M개의 줄에는 키를 비교한 두 학생의 번호 A, B가 주어진다. 이는 학생 A가 학생 B의 앞에 서야 한다는 의미이다.
학생들의 번호는 1번부터 N번이다.4 2 # 노드 개수, 에지 개수 4 2 3 1
첫째 줄에 학생들을 앞에서부터 줄을 세운 결과를 출력한다. 답이 여러 가지인 경우에는 아무거나 출력한다.
3 4 1 2
N(학생 수) M(비교 횟수)
A(비교 데이터 저장 인접 리스트)
indegree(진입 차수 리스트)
for M만큼 반복:
인접 리스트 데이터 저장
진입 차수 리스트 초기 데이터 저장
# 위상 정렬 수행
큐 생성
for N만큼 반복:
진입 차수 리스트의 값이 0인 학생(노드)을 큐에 삽입
while 큐가 빌 때까지:
현재 노드 = 큐에서 데이터 가져오기
현재 노드값 출력
for 현재 노드에서 갈 수 있는 노드의 개수:
타깃 노드 진입 차수 리스트값 1 감소
if 타깃 노드의 진입 차수가 0이면:
큐에 타깃 노드 추가
from collections import deque
N, M = map(int, input().split())
A = [[] for _ in range(N + 1)]
indegree = [0] * (N + 1) # 진입 차수 리스트
for i in range(M):
S, E = map(int, input().split())
A[S].append(E)
indegree[E] += 1 # 진입 차수 데이터 저장
queue = deque()
for i in range(1, N + 1):
if indegree[i] == 0:
queue.append(i)
while queue: # 위상 정렬 수행
now = queue.popleft()
print(now, end=' ')
for next in A[now]:
indegree[next] -= 1
if indegree[next] == 0:
queue.append(next)