用 heapq 实现带过期状态判断的 Dijkstra,求非负权有向图单源最短路。
OJ: luogu
题目 ID: P4779
难度:普及+/提高-
标签:Dijkstra最短路heapqpython
日期: 2026-07-17 03:00
题意
求非负权有向图中起点到每个节点的最短距离。
思路
Dijkstra 每次从堆中取当前距离最小的状态,尝试松弛所有出边。堆中可能保留旧状态,若弹出的距离不等于数组中的最新距离就跳过。
Python 知识
heapq是最小堆,元组按距离优先比较。current != distance[node]是无 decrease-key 堆的标准过期判断。print(*distance[1:])直接输出一行结果。
代码
python
import sys
from heapq import heappop, heappush
input = sys.stdin.buffer.readline
n, edges, start = map(int, input().split())
graph = [[] for _ in range(n + 1)]
for _ in range(edges):
u, v, weight = map(int, input().split())
graph[u].append((v, weight))
infinity = 10**30
distance = [infinity] * (n + 1)
distance[start] = 0
heap = [(0, start)]
while heap:
current, node = heappop(heap)
if current != distance[node]:
continue
for neighbor, weight in graph[node]:
candidate = current + weight
if candidate < distance[neighbor]:
distance[neighbor] = candidate
heappush(heap, (candidate, neighbor))
print(*distance[1:])原有 C++ 版本仍保留:
cpp
#include <bits/stdc++.h>
using namespace std;
const int MAXN = 100000 + 5;
const int MAXM = 200000 + 5;
const long long INF = (1LL << 62);
int n, m, s;
int head[MAXN], to[MAXM], nxt[MAXM], edge_cnt;
long long weight_edge[MAXM];
long long dist_arr[MAXN]; // dist_arr[u] 表示从源点 s 到 u 的当前最短路
bool done[MAXN];
struct Node {
long long dist;
int u;
bool operator<(const Node &other) const {
return dist > other.dist;
}
};
void add_edge(int u, int v, long long w) {
edge_cnt++;
to[edge_cnt] = v;
weight_edge[edge_cnt] = w;
nxt[edge_cnt] = head[u];
head[u] = edge_cnt;
}
void dijkstra() {
for (int i = 1; i <= n; i++) {
dist_arr[i] = INF;
done[i] = false;
}
priority_queue<Node> q;
dist_arr[s] = 0;
q.push({0, s});
while (!q.empty()) {
Node cur = q.top();
q.pop();
int u = cur.u;
if (done[u]) {
continue;
}
done[u] = true;
for (int i = head[u]; i != 0; i = nxt[i]) {
int v = to[i];
long long w = weight_edge[i];
if (dist_arr[v] > dist_arr[u] + w) {
dist_arr[v] = dist_arr[u] + w;
q.push({dist_arr[v], v});
}
}
}
}
int main() {
ios::sync_with_stdio(false);
cin.tie(nullptr);
cin >> n >> m >> s;
for (int i = 1; i <= m; i++) {
int u, v;
long long w;
cin >> u >> v >> w;
add_edge(u, v, w);
}
dijkstra();
for (int i = 1; i <= n; i++) {
if (i > 1) {
cout << ' ';
}
cout << dist_arr[i];
}
cout << '\n';
return 0;
}复杂度
时间 O((n+m)log n),空间 O(n+m)。
总结
非负边权优先使用堆优化 Dijkstra。