消息并行传播等价于单源最短路:哨所 v 收到命令的时刻就是 1 到 v 的最短路长,边权为正跑 Dijkstra,答案是所有 dist 的最大值,不连通输出 -1。
OJ: roj
题目 ID: 1376
难度:普及-
标签:最短路Dijkstra图论
创建: 2026-09-30 07:42
更新: 2026-10-05 12:23
后置题目
luogu P3003[USACO10DEC] Apple Delivery SB 把 A 教的「堆优化 Dijkstra 用出边松弛得到到所有点 dist」原样当子程序(main.cpp 与 A 的堆+vis+松弛结构一致),先 PB 一次取出到两送货点的距离、再从 PA1 一次取出 PA1-PA2 距离,值即 dist 数组,最后才叠加 A 未教的「只有两种送货顺序」枚举取 min。luogu P2935[USACO09JAN] Best Spot SB 的正解把 A 教的「从单源跑堆优化 Dijkstra、用出边松弛得到到所有点的 dist」原样当作子程序,对每个喜欢的牧场调用一次同一函数把距离累加,再叠加无向图对称换向与编号最小 tie-break;A 只教这一次松弛模板,B 是它的多次调用加统计。
题目描述
前线有 -1。
样例输入为 4 4 / 1 2 4 / 2 3 7 / 2 4 1 / 3 4 6,输出 11。
思路
每个哨所信使充足,收到信后能同时向所有邻居转发,所以哨所 -1。
参考代码
Python 版:
python
#!/usr/bin/env python3
# Author by Rainboy blog: https://rainboylv.com github: https://github.com/rainboylvx
# rbook: -> https://rbook.roj.ac.cn https://rbook2.roj.ac.cn
# rainboy的学习导航网站: https://idx.roj.ac.cn
# create_at: 2026-09-30 07:45
# update_at: 2026-09-30 07:45
import sys
from collections import defaultdict
from heapq import heappop, heappush
def solve() -> None:
data = iter(map(int, sys.stdin.buffer.read().split()))
n, m = next(data), next(data) # n 个哨所,m 条通信线路(无向边)
adj: dict[int, list[tuple[int, int]]] = defaultdict(list)
for _ in range(m):
u, v, w = next(data), next(data), next(data)
adj[u].append((v, w)) # 无向边两个方向都要登记
adj[v].append((u, w))
# Dijkstra:dist[t] = 命令从哨所 1 传到哨所 t 的最短天数
INF = float('inf')
dist = [INF] * (n + 1)
dist[1] = 0
heap = [(0, 1)]
while heap:
d, u = heappop(heap)
if d > dist[u]:
continue # 过期堆项,早已被更短路覆盖
for v, w in adj[u]:
nd = d + w
if nd < dist[v]:
dist[v] = nd
heappush(heap, (nd, v))
all_reached = all(d < INF for d in dist[1:]) # 哨所 1 自身必可达
ans = max(dist[1:]) if all_reached else -1
print(ans)
if __name__ == "__main__":
solve()C++ 版(同一算法):
cpp
/**
* Author by Rainboy blog: https://rainboylv.com github: https://github.com/rainboylvx
* rbook: -> https://rbook.roj.ac.cn https://rbook2.roj.ac.cn
* rainboy的学习导航网站: https://idx.roj.ac.cn
* create_at: 2026-10-05 12:23
* update_at: 2026-10-05 12:23
*/
// main.cpp:消息从哨所 1 并行扩散,求所有哨所都收到信的最短时间(单源最短路)。
#include <iostream>
using namespace std;
typedef long long ll;
const int MAXN = 105;
const ll INF = (1LL << 60);
int n, m;
ll g[MAXN][MAXN]; // g[u][v] 表示哨所 u 到哨所 v 的通信天数,INF 表示两地无直达线路
ll dist[MAXN]; // dist[v] 表示命令从指挥部(哨所 1)传到哨所 v 的最短天数
int done[MAXN]; // done[v] = 1 表示 v 的最短路已经确定
int main() {
ios::sync_with_stdio(false);
cin.tie(nullptr);
cin >> n >> m;
for (int i = 1; i <= n; i++) {
for (int j = 1; j <= n; j++) {
g[i][j] = INF;
}
g[i][i] = 0;
}
for (int e = 0; e < m; e++) {
int u, v;
ll w;
cin >> u >> v >> w;
if (w < g[u][v]) {
// 线路是双向的,两个方向都要登记;重边取较小的天数
g[u][v] = w;
g[v][u] = w;
}
}
// Dijkstra:n 很小,用邻接矩阵每次线性选出未确定点中 dist 最小的即可
for (int i = 1; i <= n; i++) {
dist[i] = INF;
}
dist[1] = 0;
for (int step = 1; step <= n; step++) {
int u = 0;
for (int v = 1; v <= n; v++) {
if (!done[v] && (u == 0 || dist[v] < dist[u])) {
u = v;
}
}
if (u == 0 || dist[u] == INF) {
// 剩下的哨所都无法从指挥部到达,提前结束
break;
}
done[u] = 1;
for (int v = 1; v <= n; v++) {
if (dist[u] + g[u][v] < dist[v]) {
dist[v] = dist[u] + g[u][v];
}
}
}
ll ans = 0; // 全部送达的时刻 = 最晚收到命令的哨所的时刻
for (int v = 1; v <= n; v++) {
if (dist[v] == INF) {
cout << -1 << "\n";
return 0;
}
if (dist[v] > ans) {
ans = dist[v];
}
}
cout << ans << "\n";
return 0;
}