BOJ_플로이드_11404 (Java)

융바오·2024년 12월 26일

Problem Solving

목록 보기
18/89

문제 링크

성능 요약

메모리: 42808 KB, 시간: 380 ms

분류

플로이드–워셜, 그래프 이론, 최단 경로

제출 일자

2024년 12월 27일 00:08:57

문제 설명

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

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

입력

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

시작 도시와 도착 도시를 연결하는 노선은 하나가 아닐 수 있다.

출력

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

풀이

느낀점

  • 플로이드 워셜 알고리즘 처음 풀어봤다. 어떤 알고리즘인지 모르겠어서 그냥 바로 개념과 원리 공부부터 했다.
  • 다익스트라가 한 지점에서 다른 지점까지의 최단 거리를 구하는 그리디스러운 알고리즘이라면, 프로이드는 모든 지점끼리의 최단 거리를 구하는 다이나믹프로그래밍에 가까운 알고리즘이다.
  • 플로이드 워셜 알고리즘의 핵심 원리는 모든 노드를 경유지로 비교해서 현재 저장된 각 경로들의 최단거리를 갱신하는 것인데, 이 방법으로 어떻게 모든 노드 사이의 최단 거리가 보장되는지 의심스러웠다. (비교해서 더 긴게 탈락했는데 다른 경유지를 통해서 후에 더 짧아지는 경우가 없을까? 싶었다)
  • 간단하게 테스트를 해봤는데 경유 순서를 바꿔도 모두 빠짐없이 비교가 가능했고, 최단거리가 나왔다.
  • 앞뒤로 비교한 경로와 비교할 경로를 통해 최단거리에서 최단거리로 연장이 되기 때문에 가능한 방법이라고 생각했다.

설계 : 10분

  • 모든 노드 간 경로에 대해 인접리스트가 아닌 인접 행렬을 생성한다.
  • 행렬 전체를 충분히 큰 값으로 채운다.(Integer.MAX_VALUE 는 쓰지 않았다. 더해서 비교하는 연산이 있어서 오버플로우 될까봐)
  • 입력되는 경로들은 시작점과 도착점이 중복될 수 있으므로 입력할때부터 최소값만 남긴다.
  • 모든 노드를 경유지로 비교하기 위해 순회한다.
  • 출발점과 도착점을 전체 노드에 대해 설정하고 경유할때와의 비교를 통해 최단거리를 갱신한다.
  • 경유지와 출발점, 도착점 중 2개 이상 일치하는 경우는 비교에서 제외한다.

코드(Java)

  • 구현 시간: 30분
/**
 * Author: yngbao97, Yuk Yejin
 * Problem: 플로이드_11404
 * Date: 2024.12.26
 */

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

public class Main {
	static BufferedReader br;
	static BufferedWriter bw;
	static StringTokenizer st;
    static final int MAX = 1_000_000_000;

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

		br = new BufferedReader(new InputStreamReader(System.in));
		bw = new BufferedWriter(new OutputStreamWriter(System.out));

        int n = Integer.parseInt(br.readLine());
        int m = Integer.parseInt(br.readLine());

        int[][] cost = new int[n][n];
        for (int i = 0; i < n; i++) {
            Arrays.fill(cost[i], MAX);
        }

        for (int i = 0; i < m; i++) {
            st = new StringTokenizer(br.readLine(), " ");
            int start = Integer.parseInt(st.nextToken()) - 1;
            int end = Integer.parseInt(st.nextToken()) - 1;
            int c = Integer.parseInt(st.nextToken());
            cost[start][end] = Math.min(cost[start][end], c);
        }

        for (int v = 0; v < n; v++) {
            for (int start = 0; start < n; start++) {
                if (start == v) continue;
                for (int end = 0; end < n; end++) {
                    if (start == end || v == end) continue;
                    cost[start][end] = Math.min(cost[start][end], cost[start][v] + cost[v][end]);
                }
            }
        }

        StringBuilder sb = new StringBuilder();
        for (int i = 0; i < n; i++) {
            for (int j = 0; j < n; j++) {
                if (cost[i][j] == MAX) cost[i][j] = 0;
                sb.append(cost[i][j]).append(" ");
            }
            sb.append("\n");
        }

        bw.write(sb.toString());
		bw.flush();
		bw.close();
		br.close();
	}
}

0개의 댓글