참고하면 좋은 글 들
문제 : 2623. 음악프로그램
위상 정렬 알고리즘은 단방향 그래프에서 기존의 방향(순서)를 거스르지 않고 노드를 나열하는 알고리즘이다.
일렬로 나열한다는 것은 무슨뜻일까?
[1, 6, 2, 5, 4, 3]
은 위상 정렬된 배열이다.[4, 6, 2, 5, 1, 3]
은 위상 정렬되지 않은 배열이다.c
가 있다고 하자.1 | 2 | 3 | 4 | 5 | 6 | |
---|---|---|---|---|---|---|
a | 0 | 1 | 2 | 2 | 1 | 0 |
b | [4] | [3, 5] | [ ] | [3] | [4] | [2] |
a[4] = 2
이며b[4] = [3]
이다.a[2] = 1
이며b[2] = [3, 5]
이다.a[i] = 0
이라는 것은 나보다 먼저 정렬되어야 할 노드가 하나도 남지 않은 것을 의미한다. 즉 내가 정렬되면 된다.
여기서는 큐를 이용하여 노드를 저장한다.
que = [1, 6]
b[i]
를 이용해 a
를 업데이트한다.b[6]
에 저장된 노드들은 자신이 기다려야 할 노드가 하나 줄었다는 것이다.b[6] = [2]
이므로 a[2]
의 값을 하나 빼주면 된다.a[2] - 1 = 0
이 되므로 정렬될수 있는 새로운 노드가 생겼다. 2를 큐에 append하면 된다.a[i] = 0
을 만족하는 1, 6을 정렬하면 다음과 같이 업데이트 된다.
1 2 3 4 5 6 a 0 0 2 1 1 0 b [4] [3, 5] [ ] [3] [4] [2]
c = [1, 6]
que = [2]
1 2 3 4 5 6 a 0 0 1 1 0 0 b [4] [3, 5] [ ] [3] [4] [2]
c = [1, 6, 2]
que = [5]
1 2 3 4 5 6 a 0 0 1 0 0 0 b [4] [3, 5] [ ] [3] [4] [2]
c = [1, 6, 2, 5]
que = [4]
1 2 3 4 5 6 a 0 0 0 0 0 0 b [4] [3, 5] [ ] [3] [4] [2]
c = [1, 6, 2, 5, 4]
que = [3]
1 2 3 4 5 6 a 0 0 0 0 0 0 b [4] [3, 5] [ ] [3] [4] [2]
c = [1, 6, 2, 5, 4, 3]
que = []
---> 반복 종료
c = [1, 6, 2, 5, 4, 3]
의 위상 정렬된 리스트를 얻을 수 있다.예제
6 3
3 1 4 3
4 6 2 5 4
2 2 3
사실 음악프로그램에 있는 문제가 바로 위에서 풀었던 예제이다.
먼저 출연해야 하는 가수가 먼저 정렬되어야 하는 노드와 같다.
import sys
from collections import deque
input = sys.stdin.readline
N, M = map(int, input().split())
# 자신보다 먼저 불러야하는 가수의 수 (위상정렬)
a = [0] * (N+1)
a[0] = -1
# 자신 뒤에 불러야하는 가수를 저장하는 배열
b = [[] for _ in range(N+1)]
for _ in range(M):
temp = list(map(int, input().split()))
length = temp[0]
# 먼저 불러야하는 사람 수, 뒷 순서로 불러야할 사람 업데이트
# 첫번째 부르는 사람은 앞사람이 없으므로 두번째부터 시작
for i in range(2, length+1):
prev_s = temp[i-1]
s = temp[i]
a[s] += 1
b[prev_s].append(s)
# 위상정렬 위해 큐 초기화
que = deque()
for idx, num in enumerate(num_prev):
if not num:
que.append(idx)
# 위상정렬
c = []
while que:
s = que.popleft()
for s_next in b[s]:
a[s_next] -= 1
# 자신 앞에 부를 사람이 없게되면 큐에 추가
if not a[s_next]:
que.append(s_next)
# 정렬
c.append(s)
# 모든 가수가 노래를 부를 수 있는 경우 순서대로 출력, 아니면 0 출력
if len(answer) == N:
[print(s) for s in answer]
else:
print(0)