다익스트라 알고리즘

Ryu·2023년 6월 19일
0

알고리즘

목록 보기
12/14

다익스트라 최단 경로 알고리즘

  • 특정한 노드에서 출발하여 다른 모든 노드로 가는 최단 경로를 계산합니다.
  • 다익스트라 최단 경로 알고리즘은 음의 간선이 없을 때 정상적으로 동작합니다.
  • 다익스트라 최단 경로 알고리즘은 그리디 알고리즘으로 분류됩니다.
    - 매 상황에서 가장 비용이 적은 노드를 선택해 임의의 과정을 반복합니다.

동작 과정

  1. 출발 노드를 설정합니다.
  2. 최단 경로 테이블을 초기화합니다.
  3. 방문하지 않은 노드 중에서 최단 거리가 가장 짧은 노드를 선택합니다.
  4. 해당 노드를 거쳐 다른 노드로 가는 비용을 계산하여 최단 거리 테이블을 갱신합니다.
  5. 3번과 4번 과정을 반복합니다.

동작 예시

[초기 상태] 그래프를 준비하고 출발 노드를 설정합니다.

[Step 1] 방문하지 않은 노드 중에서 최단 거리가 가장 짧은 노드인 1번 노드를 처리합니다.
1번 노드에 인접한 노드를 확인하여 최단 경로 테이블을 갱신합니다.

[Step 2] 방문하지 않은 노드 중 최단 거리가 가장 짧은 노드인 4번 노드를 처리합니다.


[Step 3] 방문하지 않은 노드 중 최단 거리가 가장 짧은 노드인 2번 노드를 처리합니다. 거리가 같은 노드가 있다면 일반적으로 번호가 낮은 노드부터 처리합니다.

[Step 4] 방문하지 않은 노드 중 최단 거리가 가장 짧은 노드인 5번 노드를 처리합니다.

[Step 5] 방문하지 않은 노드 중 최단 거리가 가장 짧은 노드인 3번 노드를 처리합니다.

[Step 5] 방문하지 않은 노드 중 최단 거리가 가장 짧은 노드인 6번 노드를 처리합니다.

다익스트라 알고리즘의 특징

  • 매 상황에서 방문하지 않은 노드 중 가장 비용이 적은 노드를 선택해 임의의 과정을 반복합니다. -> 그리디 알고리즘
  • 단계를 거치며 한 번 처리된 노드의 최단 거리는 고정되어 더 이상 바뀌지 않습니다.
  • 다익스트라 알고리즘을 수행한 뒤에 테이블에 각 노드까지의 최단 거리 정보가 저장됩니다.

성능 분석

위 동작 과정대로 탐색한다면 O(V)번에 걸쳐서 최단 거리가 가장 짧은 노드를 매번 선형 탐색해야 합니다. 따라서 전체 시간 복잡도는 O(V^2)입니다.

일반적으로 코딩 테스트의 최단 경로 문제에서 전체 노드의 개수가 5,000개 이하라면 이 코드로 문제를 해결할 수 있습니다.
하지만 노드의 개수가 10,000개를 넘어가는 문제라면 어떻게 해야 할까요?

이 문제를 해결하기 위해 힙(Heap) 자료구조를 이용합니다.
힙 자료구조를 이용하여 단계마다 방문하지 않은 노드 중 최단 거리가 가장 짧은 노드를 선택합니다.
다익스트라 알고리즘이 동작하는 기본 원리는 동일합니다.

  • 현재 가장 가까운 노드를 저장해 놓기 위해 힙 자료구조를 추가적으로 이용한다는 점이 다릅니다.
  • 현재의 최단 거리가 가장 짧은 노드를 선택해야 하므로 최소 힙을 사용합니다.

구현 방법

[최소 힙 이용]

import heapq
import sys
input = sys.stdin.readline
INF = int(1e9) # 무한을 의미하는 값으로 10억을 설정

# 노드의 개수, 간선의 개수를 입력받기
n, m = map(int, input().split())
# 시작 노드 번호를 입력받기
start = int(input())
# 각 노드에 연결되어 있는 노드에 대한 정보를 담는 리스트를 만들기
graph = [[] for i in range(n + 1)]
# 최단 거리 테이블을 모두 무한으로 초기화
distance = [INF] * (n + 1)

# 모든 간선 정보를 입력받기
for _ in range(m):
    a, b, c = map(int, input().split())
    # a번 노드에서 b번 노드로 가는 비용이 c라는 의미
    graph[a].append((b, c))

def dijkstra(start):
    q = []
    # 시작 노드로 가기 위한 최단 경로는 0으로 설정하여, 큐에 삽입
    heapq.heappush(q, (0, start))
    distance[start] = 0
    while q: # 큐가 비어있지 않다면
        # 가장 최단 거리가 짧은 노드에 대한 정보 꺼내기
        dist, now = heapq.heappop(q)
        # 현재 노드가 이미 처리된 적이 있는 노드라면 무시
        if distance[now] < dist:
            continue
        # 현재 노드와 연결된 다른 인접한 노드들을 확인
        for i in graph[now]:
            cost = dist + i[1]
            # 현재 노드를 거쳐서, 다른 노드로 이동하는 거리가 더 짧은 경우
            if cost < distance[i[0]]:
                distance[i[0]] = cost
                heapq.heappush(q, (cost, i[0]))

# 다익스트라 알고리즘을 수행
dijkstra(start)

# 모든 노드로 가기 위한 최단 거리를 출력
for i in range(1, n + 1):
    # 도달할 수 없는 경우, 무한(INFINITY)이라고 출력
    if distance[i] == INF:
        print("INFINITY")
    # 도달할 수 있는 경우 거리를 출력
    else:
        print(distance[i])
profile
나는야 머찐 개발자

0개의 댓글