总结:SPFA算法 队列优化 求单源最短路径

SPFA算法是求单源最短路径的一种高效算法,能处理负权边问题。它通过队列优化减少了冗余操作。在初始化后,循环处理直到队列为空,同时通过对比前一次数据来检测负权环并提前结束,从而提高效率。Dijkstra算法配合堆优化可以进一步降低时间复杂度到O(m + n) log(n)。
摘要由CSDN通过智能技术生成

SPFA(Shortest Path Faster Algorithm)(队列优化)算法是求单源最短路径的一种算法,
它还有一个重要的功能是 判负环 (在差分约束系统中会得以体现),
在Bellman-ford算法的基础上加上一个队列优化
减少了冗余的松弛操作,是一种高效的最短路算法。

举例:
在这里插入图片描述

思路:

就是把dijkstra算法中对起始点到其他点的距离的最小值的代码换成了用一个队列去进行判断。其他的同dijkstra算法相同。



初始化:
除源点赋0外,其他都赋值无穷
在这里插入图片描述
此时把v1加入队列,
现在开始进入循环,直到队列为空才退出循环
在这里插入图片描述
在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

Bellman-flod算法

Djikstra算法无法解决负权边问题,但是这个算法可以解决,并且它的核心语句只有四行,堪称完美。 这里同理,循环n-1次,因为n个点最多的边数是n-1条。 因为这个算法可以检测是否存在负权边,如果存在负权边,则无最短路径,若未出现负权边,则得出结果

我们增加一个pro数组来记录上一次的数据,如果更新后数据未变,则说明所有点的最短路径已经求得,提前结束,可提高效率。

负权检测,若再进行一次松弛,数组改变了,则说明这个图一定含负边权。

注:一般使用该算法来解决存在负边权的题目。

Dijsktra + heap 优化

使用优先队列,每次找寻最小距离的点,这里有一个技巧,因为greater对pair的比较,是先比较第一个的,所以把dis[i]放在第一位。

这里如果使用邻接表+优先队列来存储,可以将时间复杂度优化至O(m + n) log(n)O(m+n)log(n),该算法时间复杂度小于O(n2)

当存在大量边的情况下,可以考虑使用邻接表存图。

#include <bits/stdc++.h>
using namespace std;
const int INF = 0x3f3f3f3f;
const int N = 205;
typedef pair<int, int> P;
int arr[N][N];
int dis[N];
bool vis[N];
int n, m, st, ed;
 
inline void init()
{
    memset(dis, INF, sizeof dis);
    memset(vis, false, sizeof vis);
    for(int i = 0; i < n; ++i)
        for(int j = 0; j < n; ++j)
            arr[i][j] = (i == j ? 0 : INF);
}
 
void Dijkstra()
{
    dis[st] = 0;
    priority_queue<P, vector<P>, greater<P> > q;
    q.push({0, st});
    while(q.size()) {
        P now = q.top(); q.pop();
        int vi = now.second;
        if(vis[vi]) continue;
        vis[vi] = true;
        for(int i = 0; i < n; ++i) {
            if(!vis[i] && dis[i] > dis[vi] + arr[vi][i]) {
                dis[i] = dis[vi] + arr[vi][i];
                q.push({dis[i], i});
            }
 
        }
    }
}
 
int main()
{
    int a, b, c;
    while(cin >> n >> m) {
        init();
        for(int i = 0; i < m; ++i) {
            cin >> a >> b >> c;
            arr[a][b] = arr[b][a] = min(arr[a][b], c);
        }
        cin >> st >> ed;
        Dijkstra();
        cout << (dis[ed] == INF ? -1 : dis[ed]) << endl;
    }
    return 0;
}

参考
https://blog.csdn.net/menshu1892/article/details/79859060?tdsourcetag=s_pcqq_aiomsg

https://blog.csdn.net/menshu1892/article/details/79859060

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值