結果

問題 No.3653 Space-Time Courier
コンテスト
ユーザー 市川瑚麻
提出日時 2026-09-06 20:08:35
言語 C++23(gcc16)
(gcc 16.1.0 + boost 1.92.0 + ACL)
コンパイル:
g++-16 -O2 -lm -std=c++23 -Wuninitialized -DONLINE_JUDGE -o a.out _filename_
実行:
./a.out
結果
AC  
実行時間 566 ms / 4,000 ms
+ 44µs
コード長 2,962 bytes
記録
記録タグの例:
初AC ショートコード 純ショートコード 純主流ショートコード 最速実行時間
コンパイル時間 4,346 ms
コンパイル使用メモリ 268,564 KB
実行使用メモリ 6,272 KB
最終ジャッジ日時 2026-09-06 20:08:50
合計ジャッジ時間 9,829 ms
ジャッジサーバーID
(参考情報)
judge2_0 / judge3_1
このコードへのチャレンジ
(要ログイン)
ファイルパターン 結果
sample AC * 2
other AC * 28
権限があれば一括ダウンロードができます

ソースコード

diff #
raw source code

#include <iostream>
#include <vector>
#include <queue>
#include <algorithm>
#include <print>

using namespace std;

const long long INF = 1e18;

struct Edge {
    int to;
    long long weight;
};

int main() {
    ios_base::sync_with_stdio(false);
    cin.tie(nullptr);

    int n, m;
    if (!(cin >> n >> m)) return 0;

    vector<long long> p(n + 1);
    for (int i = 1; i <= n; ++i) {
        cin >> p[i];
    }

    vector<vector<Edge>> adj(n + 1);
    for (int i = 0; i < m; ++i) {
        int u, v;
        long long t;
        cin >> u >> v >> t;
        adj[u].push_back({v, t});
    }

    // 1. 超頂点 0 を使って SPFA を 1 回だけ回し、ポテンシャル h を計算
    vector<long long> h(n + 1, 0);
    vector<bool> in_queue(n + 1, true);
    queue<int> q;
    for (int i = 1; i <= n; ++i) q.push(i);

    while (!q.empty()) {
        int u = q.front();
        q.pop();
        in_queue[u] = false;

        for (const auto& edge : adj[u]) {
            if (h[u] + edge.weight < h[edge.to]) {
                h[edge.to] = h[u] + edge.weight;
                if (!in_queue[edge.to]) {
                    q.push(edge.to);
                    in_queue[edge.to] = true;
                }
            }
        }
    }

    // 2. 各ノードからダイクストラ法を N 回回す
    long long min_cost = INF;
    long long ways = 0;

    for (int start = 1; start <= n; ++start) {
        vector<long long> dist(n + 1, INF);
        priority_queue<pair<long long, int>, vector<pair<long long, int>>, greater<pair<long long, int>>> pq;

        dist[start] = 0;
        pq.push({0, start});

        while (!pq.empty()) {
            auto [d, u] = pq.top();
            pq.pop();

            if (d > dist[u]) continue;

            for (const auto& edge : adj[u]) {
                // ジョンソンのアルゴリズムによる非負の重みへの変換
                long long new_weight = edge.weight + h[u] - h[edge.to];
                if (dist[u] + new_weight < dist[edge.to]) {
                    dist[edge.to] = dist[u] + new_weight;
                    pq.push({dist[edge.to], edge.to});
                }
            }
        }

        // 3. 元の最短距離に戻してコストを更新
        for (int target = 1; target <= n; ++target) {
            if (start == target || dist[target] == INF) continue;

            // 元の最短経路の距離を逆算: dist_real = dist_potential - h[start] + h[target]
            long long real_dist = dist[target] - h[start] + h[target];
            long long current_cost = real_dist + p[start] + p[target];

            if (current_cost < min_cost) {
                min_cost = current_cost;
                ways = 1;
            } else if (current_cost == min_cost) {
                ways++;
            }
        }
    }

    if (min_cost == INF) {
        std::println("-1");
    } else {
        std::println("{} {}", min_cost, ways);
    }

    return 0;
}
0