문제
기록 포인트
- 위상 정렬을 수행하기 위한 요건
- 방향 그래프여야 함
- 순환이 발생하면 안됨 (역행 간선이 있으면 안됨)
- 위상 정렬을 수행하는 다양한 방법
- 진입 간선 수가 0인 정점을 하나씩 제거하며 간선을 줄여나가는 방식
- 재귀적으로 깊이 우선 탐색을 수행하여 탐색 완료된 순서를 확인하는 방식
- 그래프의 순환 여부를 판단하는 방법
- 큐/스택을 활용해 위상 정렬을 수행한 뒤 모든 정점이 정리되었는지 확인
- 만약 모든 정점이 정리되지 않았다면, 큐/스택에 추가되지 못한 정점이 있었기 때문이며, 이는 해당 정점의 진입 간선들 중 정리되지 못한 간선이 남았기 때문임
- 결과적으로 큐/스택으로 정리된 정점의 개수가 전체 정점의 개수와 일치하는지 여부를 통해 순환 여부를 판단할 수 있음
접근 방식
제출 답안
큐를 활용한 위상 정렬
import sys
from collections import deque, defaultdict
N, M = tuple(map(int, sys.stdin.readline().split()))
adj = defaultdict(list)
in_deg = [0] * (N + 1)
for _ in range(M):
singers = list(map(int, sys.stdin.readline().split()))[1:]
for i in range(len(singers)-1):
v1, v2 = singers[i], singers[i+1]
adj[v1].append(v2)
in_deg[v2] += 1
queue = deque()
for v in range(1, N+1):
if in_deg[v] == 0:
queue.append(v)
answers = []
while queue:
v1 = queue.popleft()
answers.append(v1)
for v2 in adj[v1]:
in_deg[v2] -= 1
if in_deg[v2] == 0:
queue.append(v2)
if len(answers) == N:
for singer in answers:
print(singer)
else:
print(0)
스택을 활용한 위상 정렬
import sys
from collections import defaultdict
N, M = tuple(map(int, sys.stdin.readline().split()))
adj = defaultdict(list)
in_deg = [0] * (N + 1)
for _ in range(M):
singers = list(map(int, sys.stdin.readline().split()))[1:]
for i in range(len(singers)-1):
v1, v2 = singers[i], singers[i+1]
adj[v1].append(v2)
in_deg[v2] += 1
stack = []
for v in range(1, N+1):
if in_deg[v] == 0:
stack.append(v)
answers = []
while stack:
v1 = stack.pop()
answers.append(v1)
for v2 in adj[v1]:
in_deg[v2] -= 1
if in_deg[v2] == 0:
stack.append(v2)
if len(answers) == N:
for singer in answers:
print(singer)
else:
print(0)
재귀를 활용한 방식
import sys
from collections import deque, defaultdict
N, M = tuple(map(int, sys.stdin.readline().split()))
adj = defaultdict(list)
in_deg = [0] * (N + 1)
for _ in range(M):
singers = list(map(int, sys.stdin.readline().split()))[1:]
for i in range(len(singers)-1):
v1, v2 = singers[i], singers[i+1]
adj[v1].append(v2)
in_deg[v2] += 1
def DFS_visit(adj, v1, visited, stack):
if v1 in visited:
return True
if v1 in stack:
return False
stack.append(v1)
if v1 in adj:
for v2 in adj[v1]:
if not DFS_visit(adj, v2, visited, stack):
return False
stack.pop()
visited.append(v1)
return True
visited = []
stack = []
for v1 in range(1, N+1):
if not DFS_visit(adj, v1, visited, stack):
break
visited.reverse()
if len(visited) == N:
for singer in visited:
print(singer)
else:
print(0)
명불허전입니다..!