벨만-포드 알고리즘(Bellman-Ford Algorithm)

벨만-포드 알고리즘(Bellman-Ford Algorithm)은 음의 가중치를 허용하는 최단 경로 찾기 알고리즘입니다.

다익스트라 알고리즘과 달리 음의 가중치가 있어도 동작하지만, 음의 사이클(negative weight cycle)이 존재할 경우 경로를 제대로 계산할 수 없습니다.

이 알고리즘은 단일 시작점에서 다른 모든 정점까지의 최단 거리를 구할 수 있습니다.

벨만-포드 알고리즘 예제

주요 코드:

function bellmanFord(edges, V, source) {
    // 거리 배열 초기화
    const dist = Array(V).fill(Infinity);
    dist[source] = 0;

    // V - 1번 간선 Relaxation 반복
    for (let i = 0; i < V - 1; i++) {
        for (const [u, v, w] of edges) {
            if (dist[u] !== Infinity && dist[u] + w < dist[v]) {
                dist[v] = dist[u] + w;
            }
        }
    }

    // 음의 사이클 존재 여부 확인
    for (const [u, v, w] of edges) {
        if (dist[u] !== Infinity && dist[u] + w < dist[v]) {
            console.log("Negative weight cycle detected");

            return null;
        }
    }

    return dist;
}

사용 예제:

// 그래프의 간선 리스트: [출발, 도착, 가중치]
const edges = [
    [0, 1, 4],
    [0, 2, 5],
    [1, 2, -3],
    [2, 3, 4],
    [3, 1, -6]
];

const V = 4; // 정점 수
const source = 0;
const result = bellmanFord(edges, V, source);

if (result !== null) {
    console.log("Shortest distances from source:", result);
}

출력 결과:

Negative weight cycle detected

// OR 음의 사이클이 없는 경우

Shortest distances from source: [0, -6, -4, 0]

개요

  • 입력: 가중치가 있는 방향을 가진 그래프 G(V, E)
  • 출력: 시작 정점으로부터 모든 정점까지의 최단 거리
  • 복잡도: O(V × E)
  • 특징:
    • 음의 가중치를 가지는 간선 허용
    • 음의 사이클 탐지 가능
    • 느리지만 일반적인 그래프에 적용 가능

용어 정리

  • Relaxation: 더 짧은 경로 발견 시 거리 갱신
  • 음의 사이클: 무한히 비용을 줄일 수 있는 사이클로 벨만-포드로 탐지 가능
  • 최단 경로의 간선 수는 V-1 이하

핵심 아이디어

  1. 최단 경로는 최대 V-1개의 간선으로 구성된다.
    • 왜냐하면 사이클이 없다고 가정하면 경로 상의 정점 수는 V 이하이므로 간선 수는 V-1 이하
  2. 그래프의 모든 간선을 V-1번 반복하면서 relax 연산을 수행한다.
    • relax(u, v)는 u에서 v로 가는 더 짧은 경로가 발견되었을 때 v의 거리를 갱신하는 것.

벨만-포드 알고리즘 단계

  1. 초기화
    • 시작 정점 s의 거리를 0으로, 나머지 정점의 거리를 무한대로 설정
  2. V-1번 간선 Relaxation 반복
    • 그래프의 모든 간선을 하나씩 확인하여 u → v 경로를 업데이트
  3. 음의 사이클 존재 확인
    • 모든 간선을 한 번 더 확인했을 때 갱신되는 값이 있으면, 음의 사이클 존재

예제

입력 그래프

  • 정점: A(시작점), B, C, D
  • 간선:
    A → B (4)
    A → C (5)
    B → C (-3)
    C → D (4)
    D → B (-6)

1 단계: 초기화

dist[A] = 0, dist[B] = ∞, dist[C] = ∞, dist[D] = ∞

2단계: Relaxation 수행 (V-1 = 3번)

1회차:

  • A→B: dist[B] = min(∞, 0+4) → 4
  • A→C: dist[C] = min(∞, 0+5) → 5
  • B→C: dist[C] = min(5, 4 + (-3)) → 1
  • C→D: dist[D] = min(∞, 1 + 4) → 5
  • D→B: dist[B] = min(4, 5 + (-6)) → -1

dist[A]=0, dist[B]=-1, dist[C]=1, dist[D]=5

2회차:

  • B→C: dist[C] = min(1, -1 + (-3)) → -4
  • C→D: dist[D] = min(5, -4 + 4) → 0
  • D→B: dist[B] = min(-1, 0 + (-6)) → -6

dist[A]=0, dist[B]=-6, dist[C]=-4, dist[D]=0

3회차:

  • 반복적인 relax로 값이 계속 갱신됨 → 음의 사이클 가능성 있음

3단계: 음의 사이클 확인

  • B→C: dist[C] = -4, dist[B] = -6, w = -3
    → dist[B] + w = -6 + (-3) = -9 < -4 ⇒ 갱신됨
    → 음의 사이클 존재

벨만-포드 알고리즘과 다익스트라 비교

항목벨만-포드다익스트라
음의 가중치가능불가능 (음의 가중치가 있으면 오작동)
알고리즘 복잡도O(VE)O((V+E) logV) (우선순위 큐 사용 시)
사이클 탐지음의 사이클 탐지 가능불가능
성능느림빠름

관련 글

알고리즘 튜토리얼