넘치게 채우기
[BOJ] 11404 - 플로이드 본문
https://www.acmicpc.net/problem/11404
BOJ - 플로이드
문제 유형: 최단 거리, 그래프, 플로이드-워셜
문제 난이도: Gold IV
시간 제한: 1초
메모리 제한: 256MB
문제
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을 출력한다.
풀이
플로이드-워셜을 이용하면, O(n^3)에 풀 수 있다.
순차적으로 경유가 가능한 간선의 범위를 조금씩 늘려가면서, 가중치 행렬의 가중치를 조정하는 방법이다.
k를 가능한 최대 경유지 번호라 하자. 1부터 n까지 서서히 열어줄 것이다.
이제, 모든 i, j쌍에 대해 간선을 업데이트해주면 된다.
adj[i][j]보다 adj[i][k] + adj[k][j]가 더 저렴하다면, 그걸로 바꾸면 된다.
최종적으로 변경된 거리를 반환한다.
코드
C++
#include <bits/stdc++.h>
#define INF 1e9
using namespace std;
int n, m;
int adj[101][101];
void floyd() {
for (int k = 1; k <= n; ++k) {
for (int i = 1; i <= n; ++i) {
for (int j = 1; j <= n; ++j) {
if (adj[i][j] > adj[i][k] + adj[k][j]) {
adj[i][j] = adj[i][k] + adj[k][j];
}
}
}
}
}
int main(int argc, char *argv[]) {
cin >> n >> m;
for (int i = 0; i <= n; ++i) {
for (int j = 0; j <= n; ++j) {
if (i != j)
adj[i][j] = INF;
else
adj[i][j] = 0;
}
}
int u, v, w;
for (int i = 0; i < m; ++i) {
cin >> u >> v >> w;
if (adj[u][v] > w)
adj[u][v] = w;
}
floyd();
for (int i = 1; i <= n; ++i) {
for (int j = 1; j <= n; ++j) {
if (adj[i][j] == INF)
adj[i][j] = 0;
cout << adj[i][j] << " ";
}
cout << "\n";
}
return 0;
}
'PS > BOJ' 카테고리의 다른 글
[BOJ] 11660 - 구간 합 구하기 5 (0) | 2024.11.15 |
---|---|
[BOJ] 10830 - 행렬 제곱 (0) | 2024.11.14 |
[BOJ] 9935 - 문자열 폭발 (0) | 2024.11.13 |
[BOJ] 11054 - 가장 긴 바이토닉 부분 수열 (0) | 2024.11.12 |
[BOJ] 1987 - 알파벳 (0) | 2024.11.11 |