본문으로 건너뛰기
김신건의 로그

다익스트라 알고리즘 (Dijkstra's Algorithm)

· 수정 · 📖 약 4분 · 1,214자/단어 #algorithm #graph #shortest-path #dijkstra
dijkstra, 다익스트라, 최단 경로, shortest path

정의

다익스트라 알고리즘 (Dijkstra’s Algorithm)음이 아닌 가중치 그래프에서 단일 시작점 s 로부터 모든 정점까지의 최단 거리를 찾는 그리디 알고리즘. Edsger W. Dijkstra 가 1956년 고안, 1959년 발표. 우선순위 큐를 쓸 경우 O((V + E) log V).

문제 상황과 동기

그래프 G(V, E) 에서 시작점 s 로부터 모든 정점까지의 최단 거리를 구하고 싶다.

  • naive (BFS): 모든 간선 가중치가 1일 때만 O(V + E). 가중치가 다르면 틀림.
  • Bellman-Ford: 음수 가중치 허용, O(VE). 음수가 없는 경우 너무 느림.
  • Dijkstra: 음이 아닌 가중치 전용, O((V + E) log V). PS 최단 경로의 사실상 표준.

핵심 통찰: 이미 확정된 정점에서 출발한 간선은 다시 안 본다. 거리 작은 순서대로 확정하면, 나중에 더 짧은 경로가 나타날 수 없다 (음수 간선 없으므로).

시각화

핵심 아이디어

invariant: dist[v] = s 에서 v 로의 최단 거리 (확정 or 후보 중 최소). 확정되지 않은 정점 중 dist 가 가장 작은 u 를 확정하고, u 의 이웃을 완화 (relax).

relax(u, v, w):
    if dist[u] + w < dist[v]:
        dist[v] = dist[u] + w
        parent[v] = u

우선순위 큐로 “확정 안 된 정점 중 dist 최소” 를 O(log V) 에 추출.

간선이 음수가 아니므로, 한번 확정된 정점은 나중에 더 짧아질 수 없다. 이것이 Bellman-Ford 와의 차이.

알고리즘

Dijkstra(G, s):
    dist[s] = 0, dist[v!=s] = ∞
    pq = priority_queue (min-heap by dist)
    pq.push((0, s))

    while pq not empty:
        (d, u) = pq.pop()
        if d > dist[u]: continue      # 이미 확정된 거리보다 큰 old entry

        for (v, w) in neighbors(u):
            if dist[u] + w < dist[v]:
                dist[v] = dist[u] + w
                pq.push((dist[v], v))

구현

// O((V+E) log V) 우선순위 큐 Dijkstra
#include <bits/stdc++.h>
using namespace std;
typedef pair<int,int> pii;  // (dist, node)

int main() {
  int n, m, s;
  cin >> n >> m >> s;         // n 정점, m 간선, s 시작점 (1-indexed)
  vector<vector<pii>> adj(n + 1);
  for (int i = 0; i < m; i++) {
      int u, v, w;
      cin >> u >> v >> w;
      adj[u].push_back({v, w});
  }

  vector<int> dist(n + 1, 1e9);
  priority_queue<pii, vector<pii>, greater<pii>> pq;
  dist[s] = 0;
  pq.push({0, s});

  while (!pq.empty()) {
      auto [d, u] = pq.top(); pq.pop();
      if (d > dist[u]) continue;   // old entry

      for (auto [v, w] : adj[u]) {
          if (dist[u] + w < dist[v]) {
              dist[v] = dist[u] + w;
              pq.push({dist[v], v});
          }
      }
  }

  for (int i = 1; i <= n; i++)
      cout << (dist[i] == 1e9 ? -1 : dist[i]) << " ";
}
stdin
5 6 1
1 2 2
1 3 3
2 3 1
2 4 5
3 4 2
4 5 1
결과
0 2 3 5 6

복잡도

항목
시간 (우선순위 큐)O((V + E) log V)
시간 (배열 scan)O(V^2 + E) - 밀집 그래프만
공간O(V + E)
음수 간선✗ (Bellman-Ford 필요)

증명 스케치

귀류법: 정점 u 를 확정할 때, 나중에 더 짧은 경로 s -> … -> u’ (확정) -> … -> u 가 나타난다 가정. 그럼 u’ 확정 시점에 dist[u’] < dist[u]. 음이 아닌 가중치이므로 u’ -> … -> u 경로는 dist[u’] 이상, 따라서 dist[u] 보다 짧을 수 없다. 모순.

변형 / 활용

변형설명
역방향 간선그래프를 역으로 뒤집어 “모든 정점 -> t” 구하기
경로 복원parent 배열로 역추적
K번째 최단 경로우선순위 큐에 (dist, node, k_count) 튜플
Lazy deletiondist 갱신 후 old entry 를 큐에서 제거 안 함. 꺼낼 때 skip
다중 소스가상 super source s 를 추가해 모든 시작점과 연결
Dial’s algorithm가중치가 작은 정수일 때 배열 버킷 O(V + E·W)
A* searchheuristic h(v) 추가, dist[u] + h(u) 로 우선순위

함정

1. 음수 간선

간선이 하나라도 음수면 Dijkstra 는 틀림. 벨만-포드 사용.

2. old entry skip 안 함

우선순위 큐에서 꺼낸 (d, u) 의 d 가 dist[u] 보다 크면 이미 더 짧은 경로로 확정된 것. 무시 안 하면 O(V^2) 로 폭발.

3. 1e9 vs LLONG_MAX

초기값 INF 를 LLONG_MAX 로 하면 dist[u] + w 오버플로우. 1e9 또는 1e18 정도 적당.

4. 무방향 그래프

양방향 간선은 adj[u].push_back({v, w}); adj[v].push_back({u, w}); 둘 다.

5. parent 배열

경로 복원 원할 때 완화 시점에 parent[v] = u 기록. 역추적으로 경로 출력.

BOJ 연습 문제

번호제목정답률링크
BOJ 1753최단경로28.7%kokoa-lab
BOJ 1916최소비용 구하기38.2%kokoa-lab
BOJ 4485녹색 옷 입은 애가 젤다지?46.8%kokoa-lab
BOJ 1504특정한 최단 경로30.5%kokoa-lab
BOJ 9370미확인 도착지30.1%kokoa-lab

참고

이 글의 용어 (4개)
너비 우선 탐색 (BFS)algorithm
정의 너비 우선 탐색 (Breadth-First Search, BFS) 는 그래프 G=(V, E) 에서 시작 정점 s 로부터 가까운 정점부터 순서대로 방문하는 알고리즘. 큐 (F…
벨만-포드 알고리즘 (Bellman-Ford Algorithm)algorithm
정의 벨만-포드 알고리즘 (Bellman-Ford Algorithm) 은 음수 가중치 간선을 허용하면서 단일 시작점 s 로부터 모든 정점까지의 최단 거리를 찾는 DP 기반 알고리…
우선순위 큐 (Priority Queue)algorithm
정의 우선순위 큐 (Priority Queue) 는 원소 중 최댓값 (또는 최솟값) 을 O(log N) 에 추출하는 자료구조. 내부 구현은 대개 힙 (heap). - Max-He…
플로이드-워셜 알고리즘 (Floyd-Warshall Algorithm)algorithm
정의 플로이드-워셜 알고리즘 (Floyd-Warshall Algorithm) 은 모든 정점 쌍 (i, j) 사이의 최단 거리를 구하는 DP 알고리즘. Robert W. Floyd…

💬 댓글

사이트 검색 / 명령어

검색

스크롤 = 확대/축소 · 드래그 = 이동 · 0 = 원래 크기 · ESC = 닫기