結果
| 問題 | No.3653 Space-Time Courier |
| コンテスト | |
| ユーザー |
|
| 提出日時 | 2026-09-06 20:08:35 |
| 言語 | C++23(gcc16) (gcc 16.1.0 + boost 1.92.0 + ACL) |
| 結果 |
AC
不安定
|
| 実行時間 | 566 ms / 4,000 ms |
| + 44µs | |
| コード長 | 2,962 bytes |
| 記録 | |
| コンパイル時間 | 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 |
ソースコード
#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;
}