백준 1238 - 파티 (골드3) 풀이
문제 요약
N명의 학생이 각자 집에서 X 마을로 갔다가 돌아온다. 각 학생의 왕복 거리 중 최댓값을 구하는 문제.
- 단방향 그래프, 가중치 있음
- N ≤ 1000, M ≤ 10000
접근 방식
필요한 정보
모든 학생 i에 대해 두 가지 거리가 필요하다.
i → X거리X → i거리
X → i는 X를 시작점으로 다익스트라 1번이면 전부 구해진다.
문제는 i → X인데, 시작점이 N개라 단순하게 하면 N번 다익스트라를 돌려야 한다.
역방향 그래프 아이디어
i → X의 최단경로를 뒤집으면 X → i (역방향 그래프)의 최단경로와 동일하다.
예시: A → B → C → X 라는 경로가 있으면,
간선을 전부 뒤집은 그래프에서 X → C → B → A 가 같은 비용으로 존재한다.
따라서 역방향 그래프를 만들어서 X를 시작점으로 다익스트라를 돌리면,
i → X 거리를 한 번에 전부 구할 수 있다.
결과적으로 다익스트라를 2번만 돌리면 된다.
| 그래프 | 시작점 | 구하는 것 |
|---|---|---|
| 정방향 adj | X | X → i 거리 |
| 역방향 radj | X | i → X 거리 |
구현 포인트
입력을 받을 때 정방향과 역방향을 동시에 저장한다.
u → v, 가중치 w 입력 시:
adj[u] 에 {w, v} 추가 (정방향)
radj[v] 에 {w, u} 추가 (역방향)
최종 코드
#include<bits/stdc++.h>
using namespace std;
int main()
{
ios::sync_with_stdio(false);
cin.tie(NULL);
const int INF = 1e9;
int N, M, X;
cin >> N >> M >> X;
vector<vector<pair<int, int>>> adj(N+1);
vector<vector<pair<int, int>>> radj(N+1);
for(int i = 0; i < M; i++){
int u, v, w;
cin >> u >> v >> w;
adj[u].push_back({w, v});
radj[v].push_back({w, u});
}
// X → i 거리 (정방향)
vector<int> distance(N+1, INF);
distance[X] = 0;
priority_queue<pair<int,int>, vector<pair<int,int>>, greater<pair<int,int>>> pq;
pq.push({0, X});
while(!pq.empty()){
auto [d, node] = pq.top(); pq.pop();
if(d > distance[node]) continue;
for(const auto &next : adj[node]){
auto [nw, nv] = next;
int temp = distance[node] + nw;
if(temp < distance[nv]){
distance[nv] = temp;
pq.push({distance[nv], nv});
}
}
}
// i → X 거리 (역방향 그래프에서 X 출발)
vector<int> rdistance(N+1, INF);
rdistance[X] = 0;
priority_queue<pair<int,int>, vector<pair<int,int>>, greater<pair<int,int>>> pq2;
pq2.push({0, X});
while(!pq2.empty()){
auto [d, node] = pq2.top(); pq2.pop();
if(d > rdistance[node]) continue;
for(const auto &next : radj[node]){
auto [nw, nv] = next;
int temp = rdistance[node] + nw;
if(temp < rdistance[nv]){
rdistance[nv] = temp;
pq2.push({rdistance[nv], nv});
}
}
}
int result = 0;
for(int i = 1; i <= N; i++){
result = max(result, distance[i] + rdistance[i]);
}
cout << result;
return 0;
}
복잡도
| | N × 다익스트라 | 역방향 그래프 | |---|---|---| | 시간복잡도 | O(N × (N+M) log N) | O((N+M) log N) | | 다익스트라 횟수 | N번 | 2번 |
배운 점
역방향 그래프는 "모든 노드 → 특정 노드" 거리를 한 번에 구해야 할 때 강력한 도구다.
입력 시radj[v].push_back({w, u})한 줄만 추가하면 구현도 간단하다.
위상정렬, SCC 등 다른 그래프 문제에서도 역방향 그래프가 핵심으로 등장하니 기억해두자.