728x90
■ 위상 정렬
- 순서가 정해져 있는 일련의 작업을 차례대로 수행해야 할 때 사용할 수 있는 알고리즘.
- 방향 그래프의 모든 노드를 '방향성에 거스르지 않도록 순서대로 나열하는 것'
- "위상"은 노드들 간의 상대적인 순서나 위치를 의미한다.
■ 위상 정렬 예
'선수과목을 고려한 학습 순서 설정'
case) 컴퓨터공학과 커리큘럼
'자료구조'과목을 수강한 뒤에 '알고리즘' 강의를 수강하는 것을 권장한다.
'알고리즘'과목을 수강한 뒤에 '고급 알고리즘' 강의를 수강하는 것을 권장한다.
'고급 알고리즘'의 선수 과목은 '자료구조'와 알고리즘'이다. 라고 할 경우,
모든 과목을 수강하기 위해서는 '자료구조 → 알고리즘 → 고급 알고리즘' 순서로 강의를 수강해야 한다.
■ 위상 정렬의 진입 차수
진입차수: 특정한 노드로 '들어오는' 간선의 개수
- 위의 예시에서 '고급 알고리즘'은 2개의 선수과목을 가지고 있으므로, 진입차수가 2임을 알 수 있다.
■ 위상 정렬 알고리즘
1. 진입차수가 0인 노드를 큐에 넣는다.
2. 큐가 빌 때까지 다음의 과정을 반복한다.
1) 큐에서 원소를 꺼내 해당 노드에서 출발하는 간선을 그래프에서 제거한다.
2) 새롭게 진입차수가 0이 된 노드를 큐에 넣는다.
'''
위상 정렬 알고리즘
1. 진입차수가 0인 노드를 큐에 넣는다.
2. 큐가 빌 때까지 아래 과정을 반복한다.
1) 큐에서 원소를 꺼내 해당 노드에서 출발하는 간선을 그래프ㅔ서 제거한다.
2) 새롭게 진입차수가 0이 된 노드를 큐에 넣는다.
※ 위상 정렬 문제에서는 사이클이 발생하지 않는다고 명시하는 경우가 많다.
'''
import sys
input = sys.stdin.readline
from collections import deque
#노드의 개수와 간선의 개수 입력받기
v, e = map(int, input().split())
#모든 노드에 대한 진입차수는 0으로 초기화
indegree = [0]*(v+1) #[0, 0, 0, 0, 0, 0, 0, 0]
#각 노드에 연결된 간선 정보를 담기 위한 연결 리스트(그래프)초기화
graph = [[] for i in range(v+1)] #[[], [], [], [], [], [], [], []]
#방향 그래프의 모든 간선 정보를 입력받기
for _ in range(e):
a, b = map(int, input().split())
graph[a].append(b) #정점 A에서 B로 이동 가능
#진입차수를 1 증가
indegree[b] += 1
#indegree : [0, 0, 1, 1, 2, 1, 2, 1]
#graph: [[], [2, 5], [3, 6], [4], [7], [6], [4], []]
#위상 정렬 함수
def topology_sort():
result = [] #알고리즘 수행 결과를 담을 리스트
q = deque() #큐 기능을 위한 deque 라이브러리 사용
#처음 시작할 때는 진입차수가 0인 노드를 큐에 삽입
for i in range(1, v+1):
if indegree[i] == 0:
q.append(i)
#큐가 빌 때까지 반복
while q:
#큐에서 원소 꺼내기
now = q.popleft()
result.append(now)
print("now", now)
#해당 원소와 연결된 노드를 진입차수에서 1빼기
for i in graph[now]:
indegree[i] -= 1
#새롭게 진입차수가 0이 되는 노드를 큐에 삽입
if indegree[i] == 0:
q.append(i)
print(indegree)
print(graph)
#위상 정렬을 수행한 결과 출력
for i in result:
print(i, end=' ')
topology_sort()
728x90
'알고리즘' 카테고리의 다른 글
[해시] 프로그래머스: 완주하지 못한 선수(LV1) (0) | 2024.12.02 |
---|---|
[해시] 프로그래머스: 포켓몬(LV1) (0) | 2024.12.02 |