[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;
    }
}

相关文章: