BOJ 1162

도로포장

문제출처

문제 해석

  • N개의 도시가 주어지고, M개의 도로 정보가 주어졌을 때 K개 이하의 도로를 포장하고 갈 수 있는 최소 시간을 구하는 문제입니다.
  • 도로를 포장할 시, 해당 도로를 지나가는 데 걸리는 시간이 0으로 바뀝니다.

설계(5)

  • 다익스트라 알고리즘으로 구현이 가능합니다.
  • dist[도시개수][포장가능개수] 배열을 이용하여 얼마나 포장한 지에 따른 최소 거리를 구하도록 합니다.
  • pq에 {현재 도시, 현재 거리, 도로를 포장한 개수}정보를 추가합니다.
  • pq에 추가를 하는 조건에서 기존의 방법인 다음 dist보다 현재의 dist + 도로 시간이 작으면 갱신하도록 하는 부분을 구현합니다.
  • K개의 도로를 포장할 수 있으므로 정해진 포장 도로 개수보다 작은 경우, 포장했을 때의 결과를 pq에 추가합니다.
  • 여기서 주의할 점이 몇가지 있습니다.
  • 현재 큐에서 (dist[현재도시][사용한포장도로개수-1] == 현재 거리,dist[현재도시][사용한포장도로개수] == 현재거리) 이 두가지 경우를 모두 포함하지 않으면 다음 탐색을 하지 않도록 하였습니다. 이전의 포장도로의 사용유무를 알 수 없기 때문에 해당 두가지 경우를 모두 비교하였습니다.
  • 거리를 계산하는데, 주어지는 정보의 걸리는 시간은 10^6이하인데 간선의 개수가 최고 5만개이므로(5x10^10) int형 범위를 벗어나므로 long long 형으로 선언을 해줘야 합니다.
  • 이에따라, INF도 10^11로 넉넉하게 조정을 하였습니다.
  • 모든 탐색이 끝난 후, 마지막 도시의 포장도로 개수에 따른 dist값을 최소로 갱신하여 출력합니다.

구현(15)

코드
#include <iostream>
#include <queue>
#include <vector>
#include <algorithm>
using namespace std;
#define MAXN 10001
#define INF 1e11

typedef long long ll;

struct node{
    int cur;
    ll cur_w;
    int cnt;
    bool operator < (const node& a)const{
        return a.cur_w < cur_w;
    }
};
ll dist[MAXN][21];
priority_queue<node> pq;
vector<pair<int,ll> > adj[MAXN];
int N,M,K;
void dijkstra(){
    pq.push({1,0,0});
    dist[1][0] = 0;
    while (!pq.empty()){
        int cur = pq.top().cur;
        ll cur_w = pq.top().cur_w;
        int cur_cnt = pq.top().cnt;
        pq.pop();
        if (!(dist[cur][cur_cnt-1]==cur_w|| dist[cur][cur_cnt]==cur_w)) continue;
        for (int i = 0 ; i < adj[cur].size(); i++){
            int next = adj[cur][i].first;
            int next_w = adj[cur][i].second;
            if (cur_cnt <K){
                if (dist[next][cur_cnt+1] > dist[cur][cur_cnt]){
                    dist[next][cur_cnt+1] = dist[cur][cur_cnt];
                    pq.push({next,dist[next][cur_cnt+1],cur_cnt+1});
                }
            }
            if (dist[next][cur_cnt]>next_w + cur_w){
                dist[next][cur_cnt] = next_w + cur_w;
                pq.push({next,dist[next][cur_cnt],cur_cnt});
            }
        }
    }
}
int main(){
    ios::sync_with_stdio(false);
    cin.tie(0);
    cin >> N >> M >> K;
    for (int i = 1 ; i <=N;i++){
        for (int j = 0 ;j <= K; j++){
            dist[i][j] = INF;
        }
    }
    while (M--){
        int u,v;
        ll w;
        cin >> u >> v >> w;
        adj[u].push_back({v,w});
        adj[v].push_back({u,w});
    }
    dijkstra();
    ll ans = INF;
    for (int i = 0; i <= K; i++){
        ans = min(ans,dist[N][i]);
    }
    cout << ans <<"\n";
    return 0;
}

디버깅
제출결과
  • 92ms

마무리

  • 다익스트라를 이용하는 문제였습니다. 몇가지 함정이 있어서 그런지 정답률이 낮습니다.
  • 이번 구현은 함정에 빠져들지 않고 디버깅 없이 한번에 통과하여 굉장히 뿌듯합니다.