algo — C++23 日本語リファレンス GitHub

test/yosupo/graph/shortest_path_traced.test.cpp

AC · 最終更新 2026-10-23 · GitHub

問題: https://judge.yosupo.jp/problem/shortest_path

依存するヘッダ(5)
実装
// competitive-verifier: PROBLEM https://judge.yosupo.jp/problem/shortest_path
#include <algorithm>
#include <cassert>
#include <cstdint>
#include <functional>
#include <iostream>
#include <limits>
#include <queue>
#include <utility>
#include <vector>
#include "dp/traced.hpp"
#include "graph/edge_input.hpp"
#include "graph/graph.hpp"
#include "graph/shortest_path.hpp"

using Dist = Traced<std::int64_t>;

// DP 値を Traced にしたダイクストラ法。prev 配列も復元ループも持たず、経路は Traced が運ぶ。
// 比較は cost のみなので、距離だけを求める版と時間計算量は変わらない。
std::vector<Dist> dijkstra_traced(const csr_graph<std::int64_t> &g, int s, std::int64_t inf) {
    using node = std::pair<std::int64_t, int>;
    std::vector<Dist> dp(g.size(), Dist(inf));
    std::priority_queue<node, std::vector<node>, std::greater<>> que;
    dp[s] = Dist(0);
    que.emplace(0, s);
    while (!que.empty()) {
        auto [d, v] = que.top();
        que.pop();
        if (dp[v].cost < d) continue;
        for (auto &e : g[v]) {
            if (auto cand = dp[v].then(e.weight(), e.to()); cand < dp[e.to()]) {
                dp[e.to()] = cand;
                que.emplace(cand.cost, e.to());
            }
        }
    }
    return dp;
}

int main(void) {
    int n, m, s, t;
    std::cin >> n >> m >> s >> t;
    edge_input<std::int64_t> ei(m, 0);
    auto g = ei.to_directed(n);
    constexpr std::int64_t inf = std::numeric_limits<std::int64_t>::max();

    auto dp = dijkstra_traced(g, s, inf);
    // 距離は verify 済みの shortest_path と完全一致するはず。
    auto dist = shortest_path(g, s, inf);
    for (int i = 0; i < n; ++i) assert(dp[i].cost == dist[i]);

    if (dp[t].cost == inf) {
        std::cout << -1 << '\n';
        return 0;
    }

    auto path = dp[t].to_vector();
    // 経路が実際に辺で繋がっており、重みの和が cost と一致することを確かめる。
    // 最短路の頂点は互いに異なるので、隣接リストの走査は合計 O(E) で収まる。
    std::int64_t sum = 0;
    int from = s;
    for (int to : path) {
        std::int64_t weight = inf;
        for (auto &e : g[from]) {
            if (e.to() == to) weight = std::min(weight, e.weight());
        }
        assert(weight != inf);
        sum += weight;
        from = to;
    }
    assert(from == t && sum == dp[t].cost);

    std::cout << dp[t].cost << ' ' << path.size() << '\n';
    from = s;
    for (int to : path) {
        std::cout << from << ' ' << to << '\n';
        from = to;
    }
    return 0;
}