크래프톤 정글/TIL

[크래프톤 정글 5기] week02 알고리즘 주차 열한번째 날, 파이썬 나눗셈, 위상 정렬

양선규 2024. 3. 31. 23:09
728x90
반응형

파이썬 코드에서

a = -7

b = 2

일 때,

1. int(a / b) -> -3

2. a // b -> -4

가 된다.

1번은 ab로 나눈 후 정수 형태로 바꾸기 위해 소수점 부분을 미련없이 버린다.

반면 2번의 // 연산은 내림을 수행한다. -3.5에서 내림을 하면 -4가 된다.

만약 양수인 3.5였다면 3이 되었겠지만, 음수에서는 더 작은 수가 -4기 때문에 그렇다.

이것을 신경쓰며 코드를 짤 필요가 있어 보인다.

 

DAG(Direct Acyclic Graph)

- 사이클이 없는(비순환적) 방향 그래프

 

위상 정렬(topological sort)

- 사이클이 없는 방향 그래프(DAG)에서 정점들을 순서대로 나열하는 알고리즘. “선후관계를 만족하는 정점의 순서를 찾는다.

- 순서가 정해져 있는 일련의 작업들을 차례대로 수행해야 할 때 사용할 수 있는 알고리즘이다.

- 각 정점(노드)들은 작업이나 이벤트를 나타내고, 간선은 작업 간의 선후관계를 나타낸다.

- 위상정렬로 얻은 순서는 위상 순서(topological order)라고 한다.

- 시간 복잡도는 O(V+E) 이다.

 

진입차수와 진출차수

진입차수(Indegree)

- 특정한 노드로 들어오는 간선의 개수

진출차수(Outdegree)

- 특정한 노드에서 나가는 간선의 개수

 

 

진입차수와 진출차수

 

 

위상 정렬 알고리즘의 동작 과정

1. 가장 먼저, 진입차수가 0인 노드를 큐에 넣는다.

2. 큐에서 노드를 꺼내, 해당 노드에서 나가는 간선을 그래프에서 모두 제거한다.

3. 새롭게 진입차수가 0이 된 노드를 큐에 넣는다.

4. 2번과 3번을 반복한다.

- 노드가 큐에 들어온 순서가 위상 정렬을 수행한 결과이다.

- 만약 2번을 수행했는데 진입차수가 0이 된 노드가 없다면, 그래프에 사이클이 있다는 뜻이므로 위상정렬 알고리즘을 수행할 수 없다.

- 진입차수가 0이 된 노드가 한번에 여러 개 생길 수 있기 때문에, 이것에 대한 삽입 순서는 정해져 있지 않다. 따라서 위상정렬 알고리즘의 정답은 여러개일 수 있다.

사이클이 없는 방향 그래프

 

이 그래프의 위상 정렬 순서는 “1 -> 2 -> 5 -> 3 -> 6 -> 4 -> 7” 이다.

 

파이썬 위상 정렬 알고리즘 코드

from collections import deque
import sys

input = sys.stdin.readline
N, M = map(int, input().split())
indegree = [0 for _ in range(N + 1)]  # 진입차수를 저장할 리스트, 값은 0으로 초기화해 둔다
graph = [[] for _ in range(N + 1)]
for _ in range(M):
    root, edge = map(int, input().split())
    graph[root].append(edge)  # 연결정보 저장
    indegree[edge] += 1  # 진입차수 + 1

def topological():
    queue = deque()
    result = []

    for i in range(1, N + 1):
        if indegree[i] == 0:
            queue.append(i)
   
    while queue:
        node = queue.popleft()  # 큐에서 노드 빼기
        result.append(node)  # 뺀 노드 결과에 저장 ( 큐에서 빠지는 순서가 위상 순서이다 )

        for i in graph[node]:  # 해당 노드와 연결된 노드들에 대한 반복
            indegree[i] -= 1  # 간선 지워준다
            if indegree[i] == 0:  # 만약 진입차수가 0이 되었다면 큐에 삽입
                queue.append(i)

    return result

print(topological())
 
# 8 9
# 7 8
# 1 2
# 1 5
# 2 3
# 2 6
# 3 4
# 4 7
# 5 6
# 6 4

 

이 코드의 결과는 [1, 2, 5, 3, 6, 4, 7, 8] 이다.

 

 

 

 

 

728x90
반응형