优先队列启发式最短路径快速算法(优化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(点数、边数、源点),后续 m 行 u v w 表示有向边 \(u\to v\),权值 w;
  2. 输出:存在源点可达负环则输出 Negative cycle exists;否则依次输出每个点的最短路,不可达输出 INF;
  3. 数据范围适配:使用 long long 存储距离,避免溢出。

算法选型提醒

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

^_^

相关推荐
徐小夕9 小时前
花了3个月,我们做了一款 AI 版的“飞书文档”
前端·算法·github
Robert--cao9 小时前
移动底盘与机械臂联合规划:开源算法与工程实现
算法
小豆庄10 小时前
Mac 上给视频人脸打码:本地工具的依赖、追踪与推理管线
算法·视觉检测·视频·敏捷流程·纹理贴图
星夜离尘5610 小时前
MATLAB 工程实验:从相邻块均值手写重叠 Allan 偏差,数清有效项
算法·matlab·均值算法
y1su12 小时前
Leetcode 字符串模板
java·数据结构·算法·leetcode·职场和发展·动态规划
residual_fan12 小时前
船用柴油机动态机动工况故障诊断:控制感知仿射网络(CAAN)的技术实现
人工智能·算法·数据挖掘·数据分析
其实防守也摸鱼13 小时前
Cylab在线靶场——CTF中的通用技能
linux·数据库·学习·算法·靶场·ctf·学习网络安全
蓝悦无人机13 小时前
《Planning algorithms》读书笔记——第8章 反馈运动规划
算法·读书笔记·反馈运动规划
RaaS10014 小时前
Agent Skills 进了 Linux Foundation:2.8 亿次安装,但装 skill 还没有安全规范
人工智能·算法·架构
CV爱数码14 小时前
CT 重建从零开始(五):ASTRA Toolbox 上手——几何、投影器与算法
图像处理·算法·计算机视觉·ct