优先队列启发式最短路径快速算法(优化SPFA)-HEAP_SPFA算法

简介

优先队列启发式最短路径快速算法(Heap‑SPFA)是基于 SPFA 范式改良的启发式实验性最短路算法,不具备全新理论突破,仅用于算法学习与探索。

其核心思想:沿用 SPFA 的松弛框架,将普通 FIFO 队列替换为小根优先队列,优先松弛当前预估距离更小的节点,期望减少无效松弛迭代;保留入堆次数判定源点可达负环的逻辑。

重要声明

  1. 本算法非标准工业 / 竞赛可用算法,仅作学习研究;
  2. 无负权图下行为等价堆优化 Dijkstra,但实现范式不同;
  3. 含负权图可求解最短路、可检测负环,但负环检测灵敏度低于标准队列 SPFA;
  4. 最坏时间复杂度仍为 \(O(nm)\),无理论复杂度优化;
  5. 优先队列存在常数开销,部分场景性能不如标准 SPFA。

C++ 完整实现

cpp 复制代码
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const ll INF = 1e18;

struct Edge {
    int to;
    ll w;
};

vector<vector<Edge>> g;
vector<ll> dis;
vector<int> in_cnt;    // 入堆次数,用于判源点可达负环
vector<bool> in_heap;
int n, m;
bool has_neg_cycle = false;

void HeapSPFA(int s) {
    dis.assign(n + 1, INF);
    in_cnt.assign(n + 1, 0);
    in_heap.assign(n + 1, false);
    dis[s] = 0;

    priority_queue<pair<ll, int>, vector<pair<ll, int>>, greater<>> hp;
    hp.emplace(0, s);
    in_heap[s] = true;
    in_cnt[s]++;

    while (!hp.empty() && !has_neg_cycle) {
        auto [d, u] = hp.top();
        hp.pop();
        in_heap[u] = false;

        // 跳过过期松弛项
        if (d > dis[u]) continue;

        for (auto& e : g[u]) {
            int v = e.to;
            ll w = e.w;
            if (dis[v] > dis[u] + w) {
                dis[v] = dis[u] + w;
                if (!in_heap[v]) {
                    hp.emplace(dis[v], v);
                    in_heap[v] = true;
                    in_cnt[v]++;
                    // 入堆次数>=n 说明存在源点可达负权回路
                    if (in_cnt[v] >= n) {
                        has_neg_cycle = true;
                        return;
                    }
                }
            }
        }
    }
}

int main() {
    ios::sync_with_stdio(false);
    cin.tie(0); // 兼容 C++ 旧标准
    int s;
    cin >> n >> m >> s;
    g.resize(n + 1);
    for (int i = 0; i < m; i++) {
        int u, v; ll w;
        cin >> u >> v >> w;
        g[u].push_back({v, w});
    }
    HeapSPFA(s);
    if (has_neg_cycle) {
        cout << "Negative cycle exists\n";
    } else {
        for (int i = 1; i <= n; i++) {
            if (dis[i] == INF) cout << "INF ";
            else cout << dis[i] << " ";
        }
    }
    return 0;
}

使用说明

  1. 输入格式:第一行 n m s(点数、边数、源点),后续 mu v w 表示有向边 \(u\to v\),权值 w;
  2. 输出:存在源点可达负环则输出 Negative cycle exists;否则依次输出每个点的最短路,不可达输出 INF
  3. 数据范围适配:使用 long long 存储距离,避免溢出。

算法选型提醒

  • 无负权图:优先使用堆优化 Dijkstra;
  • 带负权且需要灵敏判负环:优先使用标准队列版 SPFA;
  • Heap‑SPFA 仅作学习探索,不用于正式工程与竞赛。

^_^

相关推荐
凯瑟琳.奥古斯特42 分钟前
K次取反最大化数组和解法(力扣1005)
开发语言·c++·算法·leetcode·职场和发展
Jerry1 小时前
LeetCode 203. 移除链表元素
算法
地平线开发者1 小时前
征程 6 | 工具链 QAT ObserverBase 源码解析
算法
地平线开发者2 小时前
【地平线 征程 6 工具链进阶教程】QAT 训练常见问题和排查
算法
地平线开发者2 小时前
征程 6 | 直方图量化配置与校准实例
算法
地平线开发者2 小时前
征程 6E/M Matrix 开发评板使用系列(一):开箱与点亮
算法·自动驾驶
Jerry3 小时前
LeetCode 59. 螺旋矩阵 II
算法
可编程芯片开发3 小时前
基于FOC控制器的BLDC无刷直流电机控制系统matlab编程与仿真
算法
aaaameliaaa3 小时前
进制练习题【找出只出现一次的数字、交换两个变量(不创建临时变量)、统计二进制中1的个数、打印整数二进制的奇数位和偶数位、求两个数二进制中不同位的个数】
c语言·数据结构·笔记·算法