알고리즘 정리 - 플로이드 와샬(워셜) (백준 11404 ) [java]

Pandahun·2020년 2월 6일
0

개략

가중 그래프에서 최단 경로를 찾는 알고리즘

  • 알고리즘을 수행하게 되면 모든 꼭짓점 쌍 간의 최단 경로의 길이(가중치의 합)가 저장된다.

알고리즘

  • "모든 정점"에서 "모든 정점"까지의 최단 거리를 구하는 알고리즘

    • DP(Dynamic Programming) 형태이다.
  • 1에서 N까지의 꼭짓점 V를 가진 그래프 G

  • i에서 j까지 (1,...,k)의 경유지를 거쳐 가는 최단경로 shortPath(i,j,k-1)

    • shortPath(i,j,k)는 i에서 k-1까지 가는 경로와 k에서 j까지 가는 경로를 합친 것
    • shortPath(i,j,k) = min( shortPath(i,j,k-1), shortPath(i,k,k-1) + shortPath(k,j,k-1))라고 재귀적 표현이 가능하다.

예제 백준 -11404 플로이드

문제

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

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

입력

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

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

출력

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

풀이

우선 문제를 보면 N개의 도시에서 다른 도시로 가는 M개의 버스 노선이 있다.
그리고 각 버스는 사용하는데 비용이 든다.

여기서 한 도시에서 다른 도시로 가는 비용을 찾는 것이 아니라, 모든 도시에서 다른 모든 도시로 가는데 필요한 비용의 최소를 구하는 문제.

이 문제는 플로이드 워셜을 적용하면 간단하게 끝난다.

for (int i = 1; i <= N; i++) {
    for (int j = 1; j <= N; j++) {
        if (i == j) {
            continue;
        }
        distances[i][j] = 1000000;
    }
}

우선 전체 거리를 저장할 배열에 1,000,000을 저장해준다. 전체 비용은 10만을 넘지 않으니 최대 값을 백만으로 저장했다.
그리고 A 도시에서 A도시로 가는경우가 없으니 continue;

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 time = Integer.parseInt(st.nextToken());
	distances[start][end] = Math.min(distances[start][end], time);
}

그리고 입력받은 버스 정보 M개에 대해서 A도시에서 B도시로 가는 기존 백만과 비용의 최솟값을 저장한다.

그러면 값이 없는 정보의 경우 백만으로 초기화 되있는다.

예제를 기준으로 테이블을 채우면

12345
1023110
2INF0INF2IF
38INF011
4INFINFINF03
574INFINF0

로 배열이 초기화 된다.

여기서 모든 (A,B)의 쌍을 구하면

i에서 k, k에서 j를 가는 경우와 i,k를 가는 경우를 비교하면 된다

for (int k = 1; k <= N; k++) {
	for (int i = 1; i <= N; i++) {
		for (int j = 1; j <= N; j++) {
			distances[i][j] = Math.min(distances[i][j], (distances[i][k] + adj[k][j]));
		}
	}
}
profile
개발하는팬더

0개의 댓글