[알고리즘] 코테 유형 분석 19. 플로이드-워셜

최민길(Gale)·2023년 8월 22일
1

알고리즘

목록 보기
115/172

안녕하세요 오늘은 플로이드-워셜 알고리즘에 대해 알아보도록 하겠습니다. 플로이드-워셜 알고리즘은 그래프에서 최단 거리를 구하는 알고리즘으로 O(노드 수^3)의 시간 복잡도를 가집니다. 또한 벨만-포드 알고리즘과 유사하게 음수 가중치 간선이 있어도 수행이 가능합니다. 하지만 벨만-포드 알고리즘과의 차이점은 그래프에서 시작점을 지정하기 않고 모든 노드 간의 최단 경로를 탐색한다는 점입니다. 동적 계획법 원리를 이용해 접근하기 때문에 모든 노드의 최단 경로를 탐색할 수 있으며 A 노드에서 B 노드까지 최단 경로를 구했다고 가정했을 때 최단 경로 위에 K 노드가 존재한다면 그것을 이루는 부분 경로 역시 최단 경로라는 개념을 응용합니다.

플로이드-워셜 알고리즘의 동작 방식은 다음과 같습니다.
1. dp 배열을 선언하고 초기화 : dp[S][E] = 노드 S에서 E까지의 최단 거리

  • 이 때 S==E인 칸은 0으로, 다른 칸은 충분히 큰 값으로 초기화
  1. dp 배열에 그래프 데이터 저장 : dp[S][E] = W
  • W : 노드 S에서 노드 E로 이동하는 간선의 가중치
  1. 점화식으로 배열 업데이트 : dp[i][j] = Math.min(dp[i][j], dp[i][k]+dp[k][j])
  • 3중 for문의 형태로 반복(K,S,E 순서 / 각각 1부터 N까지 반복)

백준 11404 (플로이드) 문제를 통해 플로이드-워셜 알고리즘을 구현해보겠습니다. N개의 도시가 있을 떄 한 도시에서 출발해서 다른 도시로 도착하는 M개의 버스가 있을 때 도시 A에서 B로 가는데 필요한 비용의 최솟값을 구하는 문제입니다. 모든 도시의 비용의 최솟값을 구해야 하므로 플로이드-워셜 알고리즘을 사용합니다.

import java.util.*;
import java.io.*;

class Main{
    static int N,M;
    static long[][] dp;

    public static void main(String[] args) throws Exception{
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        N = Integer.parseInt(br.readLine());
        M = Integer.parseInt(br.readLine());
        dp = new long[N+1][N+1];
        for(int i=1;i<=N;i++){
            for(int j=1;j<=N;j++){
                if(i==j) dp[i][j] = 0;
                else dp[i][j] = Integer.MAX_VALUE;
            }
        }

        for(int i=0;i<M;i++){
            StringTokenizer st = new StringTokenizer(br.readLine());
            int s = Integer.parseInt(st.nextToken());
            int e = Integer.parseInt(st.nextToken());
            int v = Integer.parseInt(st.nextToken());
            dp[s][e] = Math.min(dp[s][e], v);
        }

        for(int k=1;k<=N;k++){
            for(int i=1;i<=N;i++){
                for(int j=1;j<=N;j++){
                    dp[i][j] = Math.min(dp[i][j], dp[i][k] + dp[k][j]);
                }
            }
        }

        for(int i=1;i<=N;i++){
            for(int j=1;j<=N;j++){
                if(dp[i][j] == Integer.MAX_VALUE) System.out.print("0 ");
                else System.out.print(dp[i][j] + " ");
            }
            System.out.println();
        }
    }
}

플로이드-워셜 알고리즘은 노드의 수가 적을 때 모든 노드의 최단 경로를 구하는 문제에서 사용됩니다. 플로이드-워셜 알고리즘은 노드 수^3의 시간 복잡도를 가지기 때문에 노드 수가 크다면 사용하기 어렵다는 단점이 있어 제한 조건을 잘 살펴봐야 합니다.

백준 11403 (경로 찾기) 문제의 경우 모든 정점에 대해 i에서 j로 가는 길이가 양수인 경로가 존재하는지를 조사하는 문제입니다. 플로이드 워셜 알고리즘의 특징을 이용하여 dp[i][k] == 1이고 dp[k][j] == 1일 경우 i와 j는 연결되어있다라는 명제를 도출할 수 있고, 이를 통해 연결 여부를 확인합니다.

백준 1389(케빈 베이컨의 6단계 법칙) 문제의 경우 유저와 친구 관계가 주어졌을 때 케빈 베이컨의 수가 가장 작은 사람을 출력하는 문제입니다. 이 문제는 인접 리스트로 구현한 후 BFS를 이용하여 풀 수 있으나 노드 수가 작기 때문에 플로이드-워셜 알고리즘을 사용할 수 있습니다. 플로이드-워셜 알고리즘을 사용하여 dp 배열을 채운 후 dp 배열의 각 행의 합인 케빈 베이컨 수를 각 행의 합의 최솟값을 가지는 행 번호를 출력합니다.

profile
저는 상황에 맞는 최적의 솔루션을 깊고 정확한 개념의 이해를 통한 다양한 방식으로 해결해오면서 지난 3년 동안 신규 서비스를 20만 회원 서비스로 성장시킨 Software Developer 최민길입니다.

0개의 댓글

관련 채용 정보