문제
- n개의 정점, m개의 간선이 주어집니다.
- 간선의 정보는 1) 시작 점, 2) 도착 점, 3) 가중치 입니다. 간선의 양방향입니다.
- 사진과 같이 시작 정점에서 다른 정점으로 최단 경로로 가기 위해 첫번째로 경유하는 정점들을 경로표로 출력하세요.
- n(1 <= n <= 200) 정점의 수, m(1 <= m <= 10000) 간선의 수
- 시간 제한 2초
- 문제 링크
접근 과정
1. 경로 추적
- 최단 경로로 이동한다고 했으니 최단 경로 알고리즘을 사용하면 됩니다. 다만, 경로를 추적해줍니다.
다익스트라 알고리즘에서, 다음과 같이 거리를 갱신하는 부분에서, 경로 추적을 넣어줍니다.
if(d[n_node] > d[c_node] + n_cost){
d[n_node] = d[c_node] + n_cost;
p[n_node] = c_node;
pq.push({n_node, d[n_node]});
}
2. 시간 복잡도 계산
- 1) 다익스트라 알고리즘 시간 복잡도 O(nlogm) n은 정점의 수, m은 간선의 수, 다익스트라를 총 n번 수행하기 때문에 O(n^2logm)
- n(1 <= n <= 200) 정점의 수, m(1 <= m <= 10000) 간선의 수 이기 때문에 O(n^2logm)은 O(4백만) 문제의 시간 제한이 2초 이기 때문에 시간안에 풀 수 있습니다.
코드
1. C++
#include <iostream>
#include <vector>
#include <queue>
#define max_val 2000005;
#define max_int 201
using namespace std;
int n, m, a, b, c;
int d[max_int];
struct info{
int cur;
int cost;
};
vector<info> v[max_int];
struct cmp{
bool operator()(const info &a, const info &b){
return a.cost > b.cost;
}
};
int p[max_int];
int main(){
scanf("%d %d", &n, &m);
for(int i=0; i<m; i++){
scanf("%d %d %d", &a, &b, &c);
v[a].push_back({b, c});
v[b].push_back({a, c});
}
priority_queue<info, vector<info>, cmp> pq;
for(int start_node=1; start_node <= n; start_node++){
for(int i=1; i<=n; i++) d[i] = max_val;
d[start_node] = 0;
pq.push({start_node, 0});
while(!pq.empty()){
info cur = pq.top();
int c_node = cur.cur;
pq.pop();
for(int i=0; i<v[c_node].size(); i++){
info next = v[c_node][i];
int n_node = next.cur;
int n_cost = next.cost;
if(d[n_node] > d[c_node] + n_cost){
d[n_node] = d[c_node] + n_cost;
p[n_node] = c_node;
pq.push({n_node, d[n_node]});
}
}
}
for(int i=1; i<=n; i++){
if(i==start_node){
printf("- ");
}
else if(p[i] == start_node){
printf("%d ", i);
}
else{
int cur_node = i;
while(true){
if(p[cur_node] == start_node){
printf("%d ", cur_node);
break;
}else{
cur_node = p[cur_node];
}
}
}
}
printf("\n");
}
}