Floyd-Warshall Algorithm 이란?

Floyd-Warshall Algorithm(플로이드-워샬 알고리즘)은 모든 점에 대해서 다른 모든 점에대한 경로를 찾을수 있고 음의 가중치를 가진 그래프에서도 사용할 수 있다.

Warshall은 그래프에서 모든 쌍의 경로 존재 여부를 찾아내는 동적 계획 알고리즘을 제안했다.

Floyd는 이를 변형하여 모든 쌍 최단 경로를 찾는 알고리즘을 고안하여 모든 쌍 최단 경로를 찾는 동적 계획 알고리즘을 플로이드-워샬 알고리즘이라고 한다.

플로이드 알고리즘의 시간 복잡도는 O(n^3)으로 다익스트라 알고리즘을 n번 사용할 때의 시간 복잡도와 동일하다. 플로이드 알고리즘을 매우 간단하며 다익스트라 알고리즘을 사용하는 것 보다 효율 적이다.

Floyd-Warshall Algorithm 과정

Floyd-Warshall Algorithm Pseudo-code

입력: 2차원 배열 D, 단 D[i,j]=간선(i,j)의 가중치, 만일 간선 (i,j)이 존재하지 않는다면, D[i,j]= inf, 모든 i에 대하여 D[i,j]=0이다.
출력: 모든 쌍의 최단 경로의 거리를 저장한 2차원 배열 D
1. for k = 1 to n
2. 	for i=1 to n (단 i!=k)
3. 		for j=1 to n (단, j!=k,j!=i)
4. 			D[i,j] = min{D[i,k]+D[k,j],D[i,j]}

FloydWarshall

Floyd-Warshall 알고리즘은 그래프에서 transitive closure을 찾는것이다.

transitive closure는 그래프 이론에서 사용되는 개념으로, 유향 그래프에서 한 정점에서 다른 모든 정점으로 가는 경로가 존재하는 경우, 두 정점은 ‘도달 가능’(reachable)하다고 말합니다. 이때, 해당 그래프에서 모든 정점 쌍 간의 도달 가능 여부를 표시한 행렬을 transitive closure 행렬이라 한다.

transitive closure 구하기: dist 배열의 값이 무한대가 아닌 경우, 해당 노드 쌍은 도달 가능합니다. 따라서, dist 배열의 값이 무한대인 노드 쌍은 도달 불가능하다고 판단할 수 있습니다. 이를 이용하여, transitive closure 행렬을 구할 수 있다.

부분 문제들을 찾은후 모든 점을 경유 가능한 점들로 고려하면서 모든 쌍의 최단 경로의 거리를 계산한다


Floyd-Warshall Algorithmm 구현

public class FloydWarshallAlgorithm {
    public static int[][] floydWarshall(int[][] D) {
        int n = D.length;

        // 거리 배열 초기화
        int[][] dist = new int[n][n];
        for (int i = 0; i < n; i++) {
            for (int j = 0; j < n; j++) {
                dist[i][j] = D[i][j];
            }
        }

        // 플로이드-와샬 알고리즘 수행
        for (int k = 0; k < n; k++) {
            for (int i = 0; i < n; i++) {
                for (int j = 0; j < n; j++) {
                    if (dist[i][k] != Integer.MAX_VALUE &&
                            dist[k][j] != Integer.MAX_VALUE &&
                            dist[i][k] + dist[k][j] < dist[i][j]) {
                        dist[i][j] = dist[i][k] + dist[k][j];
                    }
                }
            }
        }

        return dist;
    }

    public static void main(String[] args) {
        int INF = Integer.MAX_VALUE;

        int[][] D = {
                {0, INF, 3, INF},
                {2, 0, INF, INF},
                {INF, 7, 0, 1},
                {6, INF, INF, 0}
        };

        int[][] dist = floydWarshall(D);

        // 최단 경로 출력
        for (int i = 0; i < dist.length; i++) {
            for (int j = 0; j < dist.length; j++) {
                if (dist[i][j] == INF) {
                    System.out.print("INF ");
                } else {
                    System.out.print(dist[i][j] + " ");
                }
            }
            System.out.println();
        }
    }
}

실행 결과

0 10 3 4 
2 0 5 6 
7 7 0 1 
6 16 9 0