必须配合懒删除机制,因为std::priority_queue不支持降键操作,发现更短路径时只能push新条目,旧条目仍存在,pop时需检查dist[node] != current_dist以跳过过时状态,否则会导致错误。

直接用 std::priority_queue 实现 Dijkstra 是可行的,但必须配合懒删除机制,否则会算错路径或重复处理节点。
为什么 pop 时要检查距离是否过时
因为 std::priority_queue 不支持修改已入队元素的优先级(即“降键”操作)。当发现更短路径时,只能 push 新的 {dist, node},旧条目仍留在队列里。若不跳过,后续可能用已失效的高距离值去松弛邻居,导致结果错误。
- 每次
pop后,先判断dist[node] != current_dist:若不等,说明该状态已过时,直接continue - 这个检查必须放在循环开头,不能只靠
vis[node]标记——因为节点可能被多次入队,但只应处理一次最优状态 - 距离数组要用
vector<long long></long>或足够大的类型,避免溢出;初始化为LLONG_MAX而非INT_MAX,尤其边权较大时
priority_queue 的比较器怎么写才对
默认是最大堆,而 Dijkstra 需要每次取最小距离,所以必须显式指定最小堆行为。最稳妥的是用 greater<pair long int>></pair>,而不是手写 lambda 或自定义结构体(后者容易在模板推导中出错)。
- 声明方式:
priority_queue<pair long int>, vector<pair long int>>, greater<pair long int>>></pair></pair></pair> - 不要用
make_heap+push_heap:手动维护堆逻辑复杂、易错,且无法享受priority_queue的封装安全 - 第一项必须是距离,第二项是节点编号;若反着放,
greater会按节点编号排序,完全失去意义
邻接表结构和边权约束不能忽略
邻接表必须用 vector<vector int>>></vector>(或 vector<vector long int>>></vector>),外层索引是起点,内层每个 pair 是 {to, weight}。这是保证 O(E) 遍历效率的前提。
立即学习“C++免费学习笔记(深入)”;
- 边权必须 ≥ 0,否则 Dijkstra 不成立;含负权边请换
Bellman-Ford或SPFA - 无向图需双向加边:
adj[u].emplace_back(v, w); adj[v].emplace_back(u, w); - 节点编号建议从 0 开始,避免数组越界;若输入是 1-indexed,读入后立刻减 1
最容易被忽略的是:懒删除不是可选项,而是强制要求。哪怕图很小、看起来不会重复入队,只要逻辑上允许更短路径被 later 发现,就必须检查。漏掉这一行 if (dist[node] != d) continue;,调试时可能只在特定数据上失败,极难复现。


















