11404 플로이드
11404 플로이드 (c++)
문제
https://www.acmicpc.net/problem/11404
접근 방식
Graph, Floyd Warshall
마을(노드) 와 버스 (엣지) 가 주어진다.
자기 자신으로 가는 버스는 없고, A 마을에서 B 마을까지 가는 버스가 한개가 아닐 수 있다. (최소값 비교 필요)
각 마을에서 마을로 갈 수 있는 최단 거리를 구하라.
- k를 기점으로 i에서 j까지 가는 거리를 최신화하는 FW 알고리즘 사용
- N 은 100 이므로 O(N3)이라고 해도 1’000’000 이므로 1초 안에 해결 가능 (시간 제한)
- 각 엣지를 나타내는 2차원 int 배열 역시 N이 100이어도 4 * 100 * 100 = 40KB 밖에 안하므로 가능 (메모리 제한)
문제 풀이
#include <iostream>
#include <vector>
#define endl '\n'
#define INF 987654321
using namespace std;
inline int Min(int a, int b) { return a < b ? a : b; }
int N, M, a, b, c;
vector<vector<int>> v;
void Print()
{
for (int i = 1; i <= N; ++i)
{
for (int j = 1; j <= N; ++j)
{
cout << v[i][j] << ' ';
}
cout << endl;
}
}
void FW()
{
for (int k = 1; k <= N; ++k)
{
for (int i = 1; i <= N; ++i)
{
for (int j = 1; j <= N; ++j)
{
if (i == j) continue;
if (v[i][k] == 0 || v[k][j] == 0) continue;
if (v[i][j] == 0) v[i][j] = v[i][k] + v[k][j];
else v[i][j] = Min(v[i][j], v[i][k] + v[k][j]);
}
}
}
}
int main()
{
ios::sync_with_stdio(0); cin.tie(0); cout.tie(0);
cin >> N >> M;
v = vector<vector<int>>(N + 1, vector<int>(N + 1, 0));
for (int i = 1; i <= N; ++i) v[i][i] = 0;
while (M-- > 0)
{
cin >> a >> b >> c;
if (v[a][b]) v[a][b] = Min(v[a][b], c);
else v[a][b] = c;
}
FW();
Print();
return 0;
}
다시 생각해 볼 점
- 간선이 하나가 아닐 수 있다하여 최소값 비교는 잘 했었다.
- 하지만 98%에서 계속 틀렸었는데, 문제의 ‘도달할 수 없는 경우 0 을 출력하시오’ 라는 조건을 체크하지 못했기 때문이었다. (내가 자체적으로 명시한 INF = 987654321 을 출력하고 있었음)
- 처음부터 벡터를 0으로 초기화하고, 벡터에 입력받을 때와, FW 알고리즘을 수행할 때 추가 조건을 걸어주기로 했다.
- 초기화
- 기존엔 INF 로 초기화 되어있어서 v[a][b] = Min(v[a][b], c) 하면 알아서 최소값이 들어갔지만 이제는 0으로 초기화 되어있기 때문에 원하는데로 동작하지 않았다.
- a == b 인 간선은 없다고 했으므로, if (v[a][b] == 0) v[a][b] = c 를 해줬고,
- 0이 아닌 경우는 else v[a][b] = Min(v[a][b], c) 를 해줬더니 정삭 작동했다.
- FW
- 기존엔 INF로 초기화 되어있었으므로, 그냥 k, i, j로 3중 for문을 돌리면 끝났다.
- 하지만 이제 0이 초기화 값이므로,
- if (i == j) continue; 를 넣어 나 자신이 혹시나 0 이외의 값으로 초기화되는 것을 막아주고
-
if (v[i][k] == 0 v[k][j] == 0) continue; 를 넣어 경로가 없는데 더 작은 값으로 인식되는 경우를 막았다. - if (v[i][j] == 0) v[i][j] = v[i][k] + v[k][j]; 위에서 나 자신으로의 경로를 막고, 돌아가는 경로가 무한인 경우를 막았기 때문에, i에서j로 가는 경로가 무한이면 그대로 k를 경유하는 경로로 초기화 해줬다.
- else v[i][j] = Min(v[i][j], v[i][k] + v[k][i]); 마지막으로 경로가 존재하는 경우 현재 코스트와 k를 경유하는 코스트를 비교하여 최신화 해줬다.
- 초기화