코딩 테스트 [그래프] - 가장 빠른 버스 노선 구하기

유의선·2023년 10월 14일
0

n(2 ≤ n ≤ 100)개의 도시가 있다. 그리고 한 도시에서 출발해 다른 도시에 도착하는 m(1 ≤ m ≤ 100,000)개의 버스가 있다. 각 버스는 한 번만 사용할 때 필요한 비용이 있다. 모든 도시의 쌍(A, B)에 관해 도시 A에서 B로 가는데 필요한 비용의 최솟값을 구하는 프로그램을 작성하시오.

(시간 제한 1초)


입력

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

출력

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

예제 입력
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

예제 출력
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

1단계 - 문제 분석하기

모든 도시의 쌍과 관련된 최솟값을 구하는 문제이다. 그래프에서 시작점을 지정하지 않고, 모든 노드와 관련된 최소 경로를 구해야 하므로 플로이드-워셜 알고리즘을 사용하면 된다. 도시의 최대 개수도 100개로 매우 작은 편이므로 시간 복잡도가 큰 플로이드-워셜 알고리즘을 사용하기에 적합하다.

2단계 - 손으로 풀어 보기

1 버스 비용 정보를 인접 행렬에 저장한다. 먼저 인접 행렬을 초기화한 후, 주어진 버스 비용 데이터값을 인접 행렬에 저장한다.

2 플로이드-워셜 알고리즘을 수행한다. 다음 점화식을 이용한 3중 for 문으로 모든 중간 경로를 탐색한다.

  • Math.min(D[S][E], D[S][K] + D[K][E])

3 알고리즘으로 변경된 인접 행렬을 출력한다. 정답 배열을 그대로 출력하되, 값이 ∞일 때는 0을 출력한다.

3단계 - sudo코드 작성하기

N(도시 개수) M(노선 개수)
distance(노선 데이터를 저장하는 인접 행렬)

for(i -> N만큼 반복하기)
{
	for(j -> N만큼 반복하기)
    {
    	인접 행렬 초기화
    }
}

for(M만큼 반복하기)
{
	노선 데이터를 distance 행렬에 저장하기
}

for(k -> N만큼 반복)
{
	for(i -> N만큼 반복)
    {
    	for(j -> N만큼 반복)
        {
        	distance[i][j] = Math.min(distance[i][j], distance[i][k] + distance[k][j])
        }
    }
}

정답 배열 출력하기

4단계 - 코드 구현하기

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

public class Q61 {
    public static void main(String[] args) throws IOException{
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        int N = Integer.parseInt(br.readLine());
        int M = Integer.parseInt(br.readLine());
        int[][] distance = new int[N+1][N+1];

        for(int i = 1; i < N+1; i++){
            for(int j = 1; j < N+1; j++){
                if(i == j)
                    distance[i][j] = 0;
                else
                    distance[i][j] = 10000001;
            }
        }

        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());
            if(distance[S][E] > V)
                distance[S][E] = V;
        }

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

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

        br.close();
    }
}

  • Do it! 알고리즘 코딩테스트 자바 편

0개의 댓글