2252번: 줄 세우기
첫째 줄에 N(1 ≤ N ≤ 32,000), M(1 ≤ M ≤ 100,000)이 주어진다. M은 키를 비교한 회수이다. 다음 M개의 줄에는 키를 비교한 두 학생의 번호 A, B가 주어진다. 이는 학생 A가 학생 B의 앞에 서야 한다는 의
www.acmicpc.net
위상 정렬 알고리즘을 사용하면 풀 수 있습니다. 간단하게 설명하자면 어떤 노드를 방문하는데 조건이 있는 경우 위상정렬을 사용하게 됩니다.
특정 노드 A 를 방문할 때 B, C 를 선행 방문해야 한다고 가정하겠습니다. A와 B, A 와 C를 간선으로 연결하고, 각 노드에서의 들어오고 나가는 간선을 체크해줍니다.
A : 나가는 간선 0 / 들어오는 간선 2
B : 나가는 간선 1 / 들어오는 간선 0
C : 나가는 간선 1 / 들어오는 간선 0
우선 들어오는 간선이 0 인 노드를 모두 큐에 집어 넣습니다. 들어오는 간선이 0 이라는 말은 선행 조건이 없다는 말과 같으므로 큐에 넣을 수 있습니다.
queue = [B, C]
큐에 넣은 노드와 연결된 노드, 즉 큐에 넣은 노드가 선행 조건인 노드의 들어오는 간선을 -1 해줘야합니다. 해당 노드를 방문하며 선행 조건을 만족했기 때문입니다. 현재 문제에서는 나가는 간선은 신경쓰지 않아도 됩니다.
A : 나가는 간선 0 / 들어오는 간선 2 -1 -1 = 0
B : 나가는 간선 0 / 들어오는 간선 0
C : 나가는 간선 0 / 들어오는 간선 0
그리고 BFS 를 사용하는데, 다음 큐에 넣는 조건은 현재 노드와 연결되어 있으면서 들어오는 간선이 0 인 경우입니다. 이를 반복하면 됩니다.
import sys
from collections import deque
def solution(N, M, data_list):
# 큐
queue = deque([])
# 위상정렬을 위한 간선정보를 포함한 트리 [[자식 노드들], 들어오는 간선]
tree = [[[], 0] for _ in range(N+1)]
tree[0][1] = -1
# 간선 정보 입력
for parent, child in data_list:
# 자식 정보 입력
tree[parent][0].append(child)
# 자식의 들어오는 간선 + 1
tree[child][1] += 1
# 트리에서 들어오는 간선이 0 인 노드 모두 큐에 추가
for node_idx in range(len(tree)):
if not tree[node_idx][1]:
queue.append(node_idx)
# 줄세우기 리스트
line = []
# 순회
while True:
# 큐가 비면 끝
if not queue:
print(*line)
return
# 현재 노드
now_node = queue.popleft()
# 현재 노드 줄세우기 리스트에 추가
line.append(now_node)
# 현재 노드의 간선 -1 으로 중복 방지
tree[now_node][1] -= 1
# 현재 노드에 연결되어 있는 노드 간선 제거
for node in tree[now_node][0]:
tree[node][1] -= 1
# 현재 노드에 연결되어 있는 노드 중 들어오는 간선이 0 이면 큐에 삽입
for node in tree[now_node][0]:
if not tree[node][1]:
queue.append(node)
N, M = map(int, sys.stdin.readline().split())
data_list = [list(map(int, sys.stdin.readline().split())) for _ in range(M)]
solution(N, M, data_list)