플로이드 워셜 알고리즘이란


플로이드 워셜 알고리즘이란 최단 경로를 구하는 알고리즘으로 다이나믹 프로그래밍의 일종이다.

다익스트라 알고리즘과는 다르게 모든 지점에서 다른 모든 지점까지 이동하는 데 필요한 최단 경로를 구한다.

플로이드 워셜 알고리즘은 모든 노드를 각각 한번씩 주인공으로 삼는다. 이 말은 그 노드를 기준으로 특정 판단을 수행한다는 것이다.

이를테면, K 번째 노드를 주인공으로 삼았다고 가정해보자. 이 때 알고리즘은 K 를 중간에 거쳐 지나가는 모든 경우를 고려한다.

예를들어, 현재 최단 거리 테이블에 A 번째 노드에서 B 번째 노드로 이동하는 비용이 3이라고 저장되어 있다고 해보자.

이 때 K 를 주인공으로 삼은 상황에서, 알고리즘은 K 를 거치는 모든 이동 경로 경우의 수를 고려하는데, 이 때 A 에서 B 까지 이동하는 경로도 포함되어 있다.

즉 A 번째 노드에서 K 번째 노드를 거쳐 B 번 노드로 이동하는 경로를 고려한다. 만약 이 경로의 비용이 2 라고 계산되면, 알고리즘은 A에서 B 로 가는 비용을 2로 갱신한다.

그런데 A 에서 B 로 가는 경로는 K 를 주인공 삼은 단계에서 고려하는 여러 경로 중 하나에 불과하다.

알고리즘은 지금 확인하고 있는 노드 K를 제외하고 \(N-1\) 개의 노드 중 서로 다른 노드 쌍 (S, E) 을 선택 한 이후 S -> K -> E 의 거리를 확인하는 단계를 거친다.

즉 \(_{n-1}P_2\) 의 쌍을 매 단계마다 확인해야 한다.이는 \(O(N^2)\) 의 시간 복잡도를 갖는다. 이 과정을 모든 노드에 대하여 수행해야 하니 최종 시간 복잡도는 \(O(N^3)\) 이다.

매 단계에서 수행하는 구체적인 점화식은 다음과 같다.

\[D_{ab} = min(D_{ab}, D_{ak} + D_{kb})\]


한편, 플로이드 워셜 알고리즘은 모든 지점에서 다른 모든 지점까지 이동하는 데 필요한 최단 경로를 모두 구하기 때문에 2차원 리스트에 최단 거리 정보를 저장해야 한다.

코드는 다음과 같다. 기억해야 할 내용은 서로 연결되지 않은 노드 간 거리를 무한 으로 설정했다는 점이다.

아래 코드는 나동빈 님의 깃헙을 참고하였다.

#include <bits/stdc++.h>
#define INF 1e9 // 무한을 의미하는 값으로 10억을 설정

using namespace std;

// 노드의 개수(N), 간선의 개수(M)
// 노드의 개수는 최대 500개라고 가정
int n, m;
// 2차원 배열(그래프 표현)를 만들기
int graph[501][501];

int main(void) {
    cin >> n >> m;

    // 최단 거리 테이블을 모두 무한으로 초기화
    for (int i = 0; i < 501; i++) {
        fill(graph[i], graph[i] + 501, INF);
    }

    // 자기 자신에서 자기 자신으로 가는 비용은 0으로 초기화
    for (int i = 1; i <= n; i++) {
        graph[i][i] = 0;
    }

    // 각 간선에 대한 정보를 입력 받아, 그 값으로 초기화
    for (int i = 0; i < m; i++) {
        // A에서 B로 가는 비용은 C라고 설정
        int a, b, c;
        cin >> a >> b >> c;
        graph[a][b] = c;
    }

    // 점화식에 따라 플로이드 워셜 알고리즘을 수행
    for (int k = 1; k <= n; k++) {
        for (int a = 1; a <= n; a++) {
            for (int b = 1; b <= n; b++) {
                graph[a][b] = min(graph[a][b], graph[a][k] + graph[k][b]);
            }
        }
    }

    // 수행된 결과를 출력
    for (int a = 1; a <= n; a++) {
        for (int b = 1; b <= n; b++) {
            // 도달할 수 없는 경우, 무한(INFINITY)이라고 출력
            if (graph[a][b] == INF) {
                cout << "INFINITY" << ' ';
            }
            // 도달할 수 있는 경우 거리를 출력
            else {
                cout << graph[a][b] << ' ';
            }
        }
        cout << '\n';
    }
}

Reference

  1. 플로이드 와샬 알고리즘 오해 해결 [유튜브]

Leave a comment