优先队列启发式最短路径快速算法(优化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 仅作学习探索,不用于正式工程与竞赛。

^_^

相关推荐
leisoo80971 小时前
财报数据怎么排雷本地化Python构建财务异常预警系统
人工智能·python·算法
luj_17683 小时前
塔防牌:策略与卡牌的智慧碰撞
服务器·c语言·开发语言·经验分享·算法
郝学胜-神的一滴4 小时前
干货版《算法导论》17:二叉树核心原理、遍历逻辑与高阶实操全解
数据结构·c++·python·算法·计算机·编程
爱编程的小新☆4 小时前
【LeetCode】从递归到 Flood Fill:5 道题吃透 DFS 的选择、回溯与标记
java·算法·leetcode·深度优先·回溯·flood fill
Water_Sunzhipeng4 小时前
2024牛客暑期多校训练营1
算法
hetao17338374 小时前
2026-08-09~08-14 hetao1733837 的刷题记录
c++·算法
技术小黑4 小时前
RNN算法实战系列06 | LSTM 实现糖尿病探索与预测
rnn·算法·lstm
疯狂打码的少年5 小时前
【数据结构】二叉树的性质(五大性质+计算)
数据结构·笔记·算法
wabs6665 小时前
关于图论【A*算法 | 卡码网127.骑士的攻击的思考】
数据结构·算法·图论·卡码网·广搜的改进版
CIO_Alliance5 小时前
AI认知系列(3)| 数据、算法、算力、场景四要素协同
人工智能·算法·ipaas·系统集成·企业cio联盟·企业级ai化转型