[Algorithm] 다익스트라 알고리즘

다익스트라 알고리즘에 대해 정리해보았습니다. 한 정점에서 모든 정점까지의 최단 경로를 구하는 대표 알고리즘입니다.

최단 경로 시리즈플로이드-워셜(모든 쌍), 벨만-포드(음수 간선·음수 사이클)에 이어, 한 출발점에서 나머지 모든 정점까지의 최단 경로를 빠르게 구하는 알고리즘이다.

  1. 다익스트라란?
  2. 핵심 개념 이해하기
  3. 간선 완화(Relaxation)
  4. 우선순위 큐와 동작 과정
  5. 코드 구현
  6. 시간복잡도와 공간복잡도
  7. 벨만-포드·플로이드-워셜과의 비교
  8. 실전 문제 적용

🎯 1️⃣ 다익스트라란?

💡 한 문장 정의

“음수 간선이 없을 때, 한 출발점에서 모든 정점까지의 최단 경로를 구하는 그리디 알고리즘”

💡 언제 사용하는가?

  • 한 정점(출발점)에서 나머지 모든 정점까지의 최단 거리가 필요할 때
  • 간선 가중치가 모두 0 이상(비음수)일 때
  • 정점·간선이 많아서 플로이드-워셜 O(V³)을 쓰기 어려울 때

💡 특징

특징설명
시간복잡도O((V+E)log V) (우선순위 큐 사용 시)
공간복잡도O(V)
음수 간선불가능 (잘못된 결과 가능)
그래프 종류방향/무방향 모두 가능
구현 난이도중간 (우선순위 큐 활용)
성격그리디 (매 순간 가장 가까운 정점 확정)

🧠 2️⃣ 핵심 개념 이해하기

💡 알고리즘의 본질

"매 단계마다 '가장 거리가 짧은 정점'을 하나씩 확정하고,
그 정점을 통해 갈 수 있는 이웃들의 거리를 갱신해 나가는 알고리즘"

💡 dist[v]의 의미

dist[v] = 출발점(start)으로부터
          정점 v까지 도달하는 현재까지의 최소 비용
  • 한 번 확정(방문 처리)한 정점의 dist 값은 더 이상 바뀌지 않는다.
  • 음수 간선이 없기 때문에, “지금 가장 작은 dist를 가진 정점”은 이미 최단 거리가 보장된다.

💡 그리디한 선택

  • “현재 시점에서 dist가 가장 작은 정점”을 골라서 확정한다.
  • 그 정점을 거쳐 가는 경로가 더 짧아질 수 있는 이웃만 완화(relax)한다.
  • 이렇게 하면 각 정점을 최대 한 번씩만 확정 처리하면 되고, 우선순위 큐로 “가장 작은 dist”를 빠르게 꺼낼 수 있다.

🔁 3️⃣ 간선 완화(Relaxation)

💡 간선 완화란?

“간선 u → v를 이용했을 때, 출발점에서 v까지 가는 거리가 더 짧아지면 dist[v]를 갱신하는 과정”

(벨만-포드, 플로이드-워셜에서 쓰는 것과 같은 개념이다.)

💡 완화 조건

if (dist[v] > dist[u] + w) {
    dist[v] = dist[u] + w;
    // 우선순위 큐 사용 시: (dist[v], v) 다시 넣거나 갱신
}
  • u: 방금 확정한 정점
  • v: u의 이웃 정점
  • w: 간선 (u, v)의 가중치

📌 4️⃣ 우선순위 큐와 동작 과정

💡 왜 우선순위 큐를 쓰는가?

  • 매번 “dist가 가장 작은 정점”을 골라야 한다.
  • 배열로 매번 최솟값을 찾으면 O(V) → 전체 O(V²).
  • 우선순위 큐(최소 힙)를 쓰면 최솟값 추출 O(log V), 간선당 최대 1번 갱신 → O((V+E)log V).

💡 동작 흐름 (요약)

  1. 출발점 startdist[start] = 0, 나머지는 무한대(INF)로 초기화.
  2. 우선순위 큐에 (0, start) 넣기. (비용, 정점 번호)
  3. 큐가 빌 때까지:
    • 비용이 가장 작은 (d, u) 꺼내기.
    • 이미 d > dist[u] 이면 스킵 (예전에 넣은 쓸모없는 정보).
    • u를 확정했다고 보고, u와 연결된 각 간선 (u → v, 가중치 w)에 대해 완화.
    • 완화로 dist[v]가 줄어들면 (dist[v], v) 를 큐에 넣기.
  4. 종료 후 dist[]출발점에서 각 정점까지의 최단 거리.

💡 “확정”의 의미

  • 음수 간선이 없으므로, 현재 dist가 가장 작은 정점은 더 이상 다른 경로로 더 짧아질 수 없다.
  • 그래서 그 정점은 한 번만 꺼내서 이웃만 완화하면 되고, 다시 큐에 넣을 필요 없다.
  • d > dist[u] 인 경우는 “예전에 넣었던 더 나쁜 값”이므로 무시한다.

💻 5️⃣ 코드 구현

💡 인접 리스트 + 우선순위 큐 (Java)

import java.util.*;

class Dijkstra {
    static final int INF = 987654321;
    List<int[]>[] graph;  // graph[v] = { {next, cost}, ... }
    int[] dist;
    int V;

    public int[] dijkstra(int start) {
        dist = new int[V + 1];
        Arrays.fill(dist, INF);
        dist[start] = 0;

        // (비용, 정점) - 비용 기준 최소 힙
        PriorityQueue<int[]> pq = new PriorityQueue<>((a, b) -> a[0] - b[0]);
        pq.offer(new int[]{0, start});

        while (!pq.isEmpty()) {
            int[] cur = pq.poll();
            int d = cur[0], u = cur[1];

            if (d > dist[u]) continue;  // 이미 더 좋은 경로로 갱신된 경우 스킵

            for (int[] edge : graph[u]) {
                int v = edge[0], w = edge[1];
                if (dist[v] > dist[u] + w) {
                    dist[v] = dist[u] + w;
                    pq.offer(new int[]{dist[v], v});
                }
            }
        }

        return dist;
    }
}

💡 인접 행렬 버전 (정점 수가 작을 때)

  • 정점이 적고 간선이 많을 때는 인접 행렬 + 매번 최솟값 탐색으로도 구현 가능.
  • 시간복잡도 O(V²). 플로이드-워셜보다는 V가 클 때 유리할 수 있다.

⏱️ 6️⃣ 시간복잡도와 공간복잡도

💡 우선순위 큐 버전

구분복잡도설명
시간복잡도O((V+E) log V)각 간선 최대 1번 완화, PQ 삽입/삭제 log V
공간복잡도O(V)dist[], PQ에 정점 개수만큼

💡 인접 행렬 + 선형 탐색 버전

구분복잡도설명
시간복잡도O(V²)V번 반복, 매번 O(V) 최솟값
공간복잡도O(V²)인접 행렬

⚖️ 7️⃣ 벨만-포드·플로이드-워셜과의 비교

구분다익스트라벨만-포드플로이드-워셜
목적한 출발점 → 모든 정점한 출발점 → 모든 정점모든 쌍 최단 경로
음수 간선불가능가능가능 (음수 사이클 제외)
음수 사이클해당 없음탐지 가능있으면 사용 불가
시간복잡도O((V+E)log V) 또는 O(V²)O(VE)O(V³)
공간복잡도O(V)O(V)O(V²)
적용 상황출발점 하나, 음수 간선 없음음수 간선/사이클정점 적을 때, 모든 쌍

💡 언제 무엇을 쓸까?

예시 이미지1


🧪 8️⃣ 실전 문제 적용

💡 대표 문제 유형

유형설명예시 키워드
단일 출발 최단 경로한 도시에서 다른 모든 도시까지“1번 노드에서”, “한 점에서”
가중치가 양수거리, 시간, 비용이 0 이상“최소 비용”, “최단 거리”
경로 복원최단 경로에 포함된 정점/간선 출력“경로 출력”, “경로 추적”
2차원 격자칸 이동 비용을 간선으로 두고 적용“다익스트라 + BFS/격자”

💡 체크리스트

다익스트라를 쓸 때 확인할 것:

  • 음수 간선이 없는가? (있으면 벨만-포드)
  • 한 출발점에서 나머지 전체가 필요한가? (모든 쌍이면 플로이드-워셜 고려)
  • INF 값을 충분히 크게 설정했는가?
  • 같은 정점에 대한 중복 간선이 있으면 더 작은 가중치만 남겼는가?
  • d > dist[u] 스킵 처리로 이미 갱신된 노드를 건너뛰었는가?

이렇게 다익스트라까지 정리하면, 플로이드-워셜·벨만-포드와 함께 최단 경로 시리즈를 한 세트로 다룰 수 있다.