BOJ 1854

K번째 최단경로 찾기

문제출처

문제 해석

  • 1번도시에서 다른 도시로 가는 k번쨰 최단경로의 소요시간을 출력하는 문제입니다.
  • n <=1000, m<= 2*10^7, k <= 100이고 각 도시로 가는 소요시간이 주어집니다.

설계(X)

  • k번째 최단경로를 구하기 위해서 어떤 방법을 써야할 지 떠오르지 않아서 crocus님의 블로그를 통해 알게 되었습니다.
  • 다익스트라 알고리즘으로 최단경로를 찾되, 각 경로의 소요시간을 우선순위큐에 넣어 k번째 소요시간을 찾았습니다.
  • dist(각 경로의 소요시간)이 내림차순으로 되어있고, dist의 우선순위 큐 크기가 k개만 남겨놓게 되면 첫번째로 나올 소요시간은 k번째 소요시간이 됩니다.
  • dist큐에 k개가 이미 있을 경우 가장 큰 맨 앞의 큐와 다음 계산된 소요시간을 비교하여 더 작은 값을 갱신해주게 됩니다.(K~1번째로 작은 것들)
  • 만약 dist큐에 k개보다 적게 들어있는 경우, k번째 경로에 해당하는 소요시간은 없는 것이 되므로, -1을 출력합니다.

구현(X)

코드
#include <iostream>
#include <queue>
#include <vector>

using namespace std;

#define MAXN 1000
priority_queue<int> dist[MAXN];
priority_queue<pair<int,int> ,vector<pair<int,int> >, greater<> > pq;
vector<pair<int,int> > adj[MAXN];
int N,M,K;
void dijkstra(){
    pq.push({0,0});
    dist[0].push(0);
    while (!pq.empty()){
        int cur = pq.top().second;
        int cur_w = pq.top().first;
        pq.pop();
        for (int i = 0 ; i < adj[cur].size(); i++){
            int next = adj[cur][i].first;
            int next_w = adj[cur][i].second + cur_w;
            if (dist[next].size() < K){
                dist[next].push(next_w);
                pq.push({next_w,next});
            }
            else if (dist[next].top() > next_w){
                dist[next].pop();
                dist[next].push(next_w);
                pq.push({next_w,next});
            }
        }
    }
}
int main(){
    ios::sync_with_stdio(false);
    cin.tie(0);
    cin >> N >> M >> K;
    while (M--){
        int u,v,w;
        cin >> u >> v >> w;
        u--;
        v--;
        adj[u].push_back({v,w});
    }
    dijkstra();
    for (int i = 0 ; i < N; i++){
        if (dist[i].size() == K){
            cout << dist[i].top() <<"\n";
        }
        else cout << "-1\n";
    }
    return 0;
}
디버깅
제출결과

마무리

  • 다익스트라 알고리즘을 응용해서 풀 수 있는 문제였습니다. 그러나 이 응용된 부분을 생각하기 쉽지 않았습니다.