<백준> 1854

진기명기·2026년 3월 18일

코딩테스트<C++>

목록 보기
186/212

K번째 최단경로 찾기

문제
봄캠프를 마친 김진영 조교는 여러 도시를 돌며 여행을 다닐 계획이다. 그런데 김 조교는, '느림의 미학'을 중요시하는 사람이라 항상 최단경로로만 이동하는 것은 별로 좋아하지 않는다. 하지만 너무 시간이 오래 걸리는 경로도 그리 매력적인 것만은 아니어서, 적당한 타협안인 'kk번째 최단경로'를 구하길 원한다. 그를 돕기 위한 프로그램을 작성해 보자.

입력
첫째 줄에 nn, mm, kk가 주어진다. (1n10001 ≤ n ≤ 1\,000, 0m2500000 ≤ m ≤ 250\,000, 1k1001 ≤ k ≤ 100,
mk3000000mk ≤ 3\,000\,000) nnmm은 각각 김 조교가 여행을 고려하고 있는 도시들의 개수와, 도시 간에 존재하는 도로의 수이다.
이어지는 mm개의 줄에는 각각 도로의 정보를 제공하는 세 개의 정수 aa, bb, cc가 포함되어 있다. 이것은 aa번 도시에서 bb번 도시로 갈 때는 cc의 시간이 걸린다는 의미이다. (1a,bn1 ≤ a, b ≤ n, 1c10001 ≤ c ≤ 1\,000)
도시의 번호는 11번부터 nn번까지 연속하여 붙어 있으며,
11번 도시는 시작도시이다. 두 도로의 시작점과 도착점이 모두 같은 경우는 없다.

출력
nn개의 줄을 출력한다. ii번째 줄에 11번 도시에서
ii번 도시로 가는 kk번째 최단경로의 소요시간을 출력한다.경로의 소요시간은 경로 위에 있는 도로들을 따라 이동하는데 필요한 시간들의 합이다. ii번 도시에서 ii번 도시로 가는 최단경로는 00이지만, 일반적인 kk번째 최단경로는 00이 아닐 수 있음에 유의한다. 또, kk번째 최단경로가 존재하지 않으면 1-1을 출력한다. 최단경로에 같은 정점이 여러 번 포함되어도 된다.

typedef pair<int, int> edge;

int n, m, k;
vector<vector<edge>> vlist;
vector<priority_queue<int>> dist;   // 각 정점마다 K개의 거리 저장 (max heap)
priority_queue<edge, vector<edge>, greater<edge>> q;  // (거리, 정점)

void dijkstra(int start)
{
    q.push({ 0, start });
    dist[start].push(0);

    while (!q.empty())
    {
        edge current = q.top();
        q.pop();

        int cdist = current.first;
        int cnode = current.second;

        for (int i = 0; i < vlist[cnode].size(); i++)
        {
            edge temp = vlist[cnode][i];
            int next = temp.first;
            int value = temp.second;

            int newDist = cdist + value;

            // 아직 K개 미만이면 그냥 넣기
            if (dist[next].size() < k)
            {
                dist[next].push(newDist);
                q.push({ newDist, next });
            }
            // K개가 있고, 가장 큰 값보다 작으면 교체
            else if (dist[next].top() > newDist)
            {
                dist[next].pop();
                dist[next].push(newDist);
                q.push({ newDist, next });
            }
        }
    }
}

int main()
{
    ios::sync_with_stdio(false);
    cin.tie(NULL);

    cin >> n >> m >> k;

    vlist.resize(n + 1);
    dist.resize(n + 1);

    for (int i = 0; i < m; i++)
    {
        int a, b, c;
        cin >> a >> b >> c;
        vlist[a].push_back({ b, c });
    }

    dijkstra(1);

    for (int i = 1; i <= n; i++)
    {
        if (dist[i].size() == k)
            cout << dist[i].top() << "\n";
        else
            cout << -1 << "\n";
    }
}

0개의 댓글