1. 程式人生 > 實用技巧 >[CF20C] Dijkstra? - 最短路

[CF20C] Dijkstra? - 最短路

[CF20C] Dijkstra? - 最短路

Description

給出一張圖,請輸出其中任意一條可行的從點 1 到點 n 的最短路徑。

Solution

(當作是複習資料結構,默一遍 Dijkstra 板子)

Dijkstra 的核心思想是維護一個已經處理過的集合 S,每次選擇一個 \(p \notin S\)\(dist[p]\) 最小的 p,將它加入集合 S 中,並且更新所有 p 的直接後繼的距離。

實現中,我們用堆來加速查詢最小值的過程。具體地,我們在小頂堆中壓入 (距離,頂點) 的結構,每次鬆弛操作後都壓入(這樣可能會導致堆中出現重複元素,沒有關係,只要我們通過 \(vis[]\)

保證每個點只會被訪問一次即可)。

#include <bits/stdc++.h>
using namespace std;

#define int long long

signed main()
{
    ios::sync_with_stdio(false);

    int n;
    int m;

    cin >> n >> m;

    vector<int> vis(n + 2, 0), dis(n + 2, (long long)(1e18)), from(n + 2, 0);
    vector<tuple<int, int, int>> edges;
    vector<vector<pair<int, int>>> g(n + 2, vector<pair<int, int>>());

    for (int i = 1; i <= m; i++)
    {
        int t1, t2, t3;
        cin >> t1 >> t2 >> t3;
        edges.emplace_back(make_tuple(t1, t2, t3));
        g[t1].emplace_back(make_pair(t2, t3));
        g[t2].emplace_back(make_pair(t1, t3));
    }

    priority_queue<pair<int, int>, vector<pair<int, int>>, greater<pair<int, int>>> que;

    dis[1] = 0;
    que.push(make_pair(dis[1], 1));

    while (!que.empty())
    {
        auto [d, p] = que.top();
        que.pop();
        if (vis[p])
            continue;

        vis[p] = 1;
        for (auto [q, w] : g[p])
        {
            if (dis[p] + w < dis[q])
            {
                dis[q] = dis[p] + w;
                from[q] = p;
                que.push(make_pair(dis[q], q));
            }
        }
    }

    function<void(int)> print = [&](int p) -> void {
        if (p)
        {
            print(from[p]);
            cout << p << " ";
        }
    };

    if (dis[n] < 1e17)
    {
        print(n);
    }
    else
    {
        cout << -1;
    }
}