[JAVA] 백준 (골드4) 11404번 플로이드

AIR·2024년 5월 14일
0

코딩 테스트 문제 풀이

목록 보기
102/135

링크

https://www.acmicpc.net/problem/11404


문제 설명

정답률 41.877%
n(2 ≤ n ≤ 100)개의 도시가 있다. 그리고 한 도시에서 출발하여 다른 도시에 도착하는 m(1 ≤ m ≤ 100,000)개의 버스가 있다. 각 버스는 한 번 사용할 때 필요한 비용이 있다.

모든 도시의 쌍 (A, B)에 대해서 도시 A에서 B로 가는데 필요한 비용의 최솟값을 구하는 프로그램을 작성하시오.


입력 예제

  • 첫째 줄에 도시의 개수 n이 주어지고 둘째 줄에는 버스의 개수 m이 주어진다. - 그리고 셋째 줄부터 m+2줄까지 다음과 같은 버스의 정보가 주어진다.
  • 먼저 처음에는 그 버스의 출발 도시의 번호가 주어진다.
  • 버스의 정보는 버스의 시작 도시 a, 도착 도시 b, 한 번 타는데 필요한 비용 c로 이루어져 있다.
  • 시작 도시와 도착 도시가 같은 경우는 없다.
  • 비용은 100,000보다 작거나 같은 자연수이다.
  • 시작 도시와 도착 도시를 연결하는 노선은 하나가 아닐 수 있다.

5
14
1 2 2
1 3 3
1 4 1
1 5 10
2 4 2
3 4 1
3 5 1
4 5 3
3 5 10
3 1 8
1 4 2
5 1 7
3 4 2
5 2 4


출력 예제

  • n개의 줄을 출력해야 한다.
  • i번째 줄에 출력하는 j번째 숫자는 도시 i에서 j로 가는데 필요한 최소 비용이다.
  • 만약, i에서 j로 갈 수 없는 경우에는 그 자리에 0을 출력한다.

0 2 3 1 4
12 0 15 2 5
8 5 0 1 1
10 7 13 0 3
7 4 10 6 0


풀이

모든 노드끼리의 최소 경로를 구해야 한다. 이는 플로이드-워셜 알고리즘으로 해결할 수 있다. 도시의 최대 개수가 10210^2으로 O(n3)O(n^3) 시간복잡도로 가능하다.

플로이드-워셜은 인접 행렬을 이용하여 그래프를 나타낸다. 자기 자신과의 거리는 0으로 저장하고 나머지는 충분히 큰 값으로 초기화한 뒤 갱신해나간다.

dist = new int[N + 1][N + 1];
for (int i = 0; i < N + 1; i++) {
    Arrays.fill(dist[i], INF);
    for (int j = 0; j < N + 1; j++) {
        //자기 자신과의 거리는 0
        if (i == j) {
            dist[i][j] = 0;
        }
    }
}

for (int i = 0; i < M; i++) {
    st = new StringTokenizer(br.readLine());
    int start = Integer.parseInt(st.nextToken());  //시작 도시
    int end = Integer.parseInt(st.nextToken());  //도착 도시
    int cost = Integer.parseInt(st.nextToken());  //비용
    
    if (dist[start][end] > cost) {
        dist[start][end] = cost;
    }
}

그리고 플로이드-워셜 알고리즘을 수행하는데 다음 점화식을 3중 for문으로 모든 중간 경로를 탐색한다.
dist[s][e]=Math.min(dist[s][e],dist[s][k]+dist[k][e])dist[s][e] = Math.min(dist[s][e], dist[s][k] + dist[k][e])

static void floydWarshall() {
    //모든 경유지에 대해 탐색
    for (int via = 1; via <= N; via++) {
        for (int start = 1; start <= N; start++) {
            for (int end = 1; end <= N; end++) {
                int newDist = dist[start][via] + dist[via][end];
                dist[start][end] = Math.min(dist[start][end], newDist);
            }
        }
    }
}

코드

import java.io.BufferedReader;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.Arrays;
import java.util.StringTokenizer;

//백준
public class Main {

    static final int INF = 100_000_001;  //충분히 큰 값
    static int[][] dist;
    static int N;

    public static void main(String[] args) throws IOException {

        System.setIn(new FileInputStream("src/input.txt"));
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        StringTokenizer st;

        N = Integer.parseInt(br.readLine());  //도시의 개수
        int M = Integer.parseInt(br.readLine());  //버스의 개수

        //인접 행렬 초기화
        dist = new int[N + 1][N + 1];
        for (int i = 0; i < N + 1; i++) {
            Arrays.fill(dist[i], INF);
            for (int j = 0; j < N + 1; j++) {
                //자기 자신과의 거리는 0
                if (i == j) {
                    dist[i][j] = 0;
                }
            }
        }

        for (int i = 0; i < M; i++) {
            st = new StringTokenizer(br.readLine());
            int start = Integer.parseInt(st.nextToken());  //시작 도시
            int end = Integer.parseInt(st.nextToken());  //도착 도시
            int cost = Integer.parseInt(st.nextToken());  //비용

            if (dist[start][end] > cost) {
                dist[start][end] = cost;
            }
        }

        floydWarshall();

        StringBuilder sb = new StringBuilder();
        for (int i = 1; i <= N; i++) {
            for (int j = 1; j <= N; j++) {
                if (dist[i][j] == INF) {
                    sb.append(0).append(" ");
                } else {
                    sb.append(dist[i][j]).append(" ");
                }
            }
            sb.append("\n");
        }

        System.out.println(sb);
    }

    static void floydWarshall() {

        //모든 경유지에 대해 탐색
        for (int via = 1; via <= N; via++) {
            for (int start = 1; start <= N; start++) {
                for (int end = 1; end <= N; end++) {
                    int newDist = dist[start][via] + dist[via][end];
                    dist[start][end] = Math.min(dist[start][end], newDist);
                }
            }
        }

    }
}
profile
백엔드

0개의 댓글