문제 이해
- N개의 지점
- 방향이 없는 M개의 도로
- 방향이 존재하는 음의 가중치를 가진 W개의 웜홀
- 출발을 하였을 때보다 시간이 되돌아가 있는 경우가 있는지 탐색하라.
<조건>
- 시간 제한: 2초
- 메모리 제한: 512MB
<입력>
TC: 테스트 케이스의 개수 (1 ~ 5)
N: 지점의 수 (1 ~ 500, 10^2)
M: 도로의 개수(1 ~ 2,500, 10^3)
W: 웜홀의 개수(1 ~ 200, 10^2)
<출력>
- TC개의 줄에 걸쳐서 만약에 시간이 줄어들면서 출발 위치로 돌아오는 것이 가능하면 YES, 불가능하면 NO를 출력하라.
문제 풀이
음의 가중치를 가진 최단 경로 탐색이라는 점에서 '벨만-포드 알고리즘' 사용해야 함을 인지했다.
문제에서 원하는 것은 시간이 줄어들면서 출발 위치로 돌아올 수 있는지(음의 사이클이 존재하는 지 탐색하는 것)이었다.
도로가 방향성이 없으므로 양방향 모두 넣어주었고,
웜홀의 경우 음의 가중치로 넣어주어야 하기에 -1을 곱해주었다.
처음에는 모든 시작점에 대해서 벨만-포드 알고리즘을 사용했는데
88%쯤 가서 시간 초과가 나왔다.
계산해보니 최악의 경우에는 10^9으로 시간 제한 2초를 넘김을 확인하였다.
그렇다면 어떻게 해야할까?
바로 한 정점에서만 벨만-포드 알고리즘을 사용해주는 것이다.
그런데, 그렇게하면 웜홀의 방향성 때문에 문제가 되진 않을까???
라고 의문을 품으신다면 벨만-포드 알고리즘에 대해서 잘 숙지하고 있는 것이다!
그걸 해결할 답은 바로 아래 코드에 있었다.
if(dist[start] == INF) continue;
위의 코드는 벨만-포드 알고리즘에서
한 번도 방문하지 않은 정점에 대해서는 계산하지 않기 위해 사용하는 코드인데,
사실 우리는 '최단 경로의 비용을 구하고 싶은 게 아니라 음의 사이클을 확인'하고 싶다.
즉, 방문하지 않은 정점들끼리 음의 사이클을 형성한 것도 알아보고 싶은 것이다.
그렇기에 저 코드를 없앰으로써 한 정점에서 벨만-포드 알고리즘을 사용하여도
전체에서 음의 사이클이 존재하는지 않는지 알 수 있는 것이다!!!
전체 코드
#include <iostream>
#include <algorithm>
#include <vector>
#include <queue>
#include <cstring>
using namespace std;
#define INF 987654321
struct Road{
int start;
int end;
int cost;
};
long long dist[505];
int main() {
ios_base::sync_with_stdio(false);
cin.tie(nullptr);
int tc;
cin>>tc;
while(tc--){
int n, m, w;
cin>>n>>m>>w;
int s, e, t;
vector <Road> road;
for(int i = 0; i < m; i++){
cin>>s>>e>>t;
road.push_back({s, e, t});
road.push_back({e, s, t});
}
for(int i = 0; i < w; i++){
cin>>s>>e>>t;
road.push_back({s, e, -1 * t});
}
for(int i = 1; i <= n; i++) dist[i] = INF;
dist[1] = 0; //시작점
bool flag = false;
int size = road.size();
for(int t = 1; t <= n; t++){
for(int i = 0; i < size; i++){
int start = road[i].start;
int end = road[i].end;
int cost = road[i].cost;
//if(dist[start] == INF) continue; 단순 사이클의 유무만 판단하기에 없앰.
if(dist[end] > dist[start] + cost){
dist[end] = dist[start] + cost;
if(t == n){
flag = true;
break;
}
}
}
}
if(flag) cout<<"YES\n";
else cout<<"NO\n";
}
return 0;
}
벨만-포드 알고리즘에서 '음의 사이클'만을 탐색하고 싶을 때 시간 복잡도를 줄이는 방법을 배울 수 있었다!
'알고리즘 별 문제 정리 > 최단 경로 탐색' 카테고리의 다른 글
[C++] 백준 11403: 경로 찾기 (0) | 2024.09.30 |
---|