一篇文章 轻松搞懂 SPFA

概念

SPFA(Shortest Path Faster Algorithm) 和 Dijkstra算法 可谓是 单源最短路 的两大双子星了。

SPFA 由前身 Bellman-Ford-Moore(Bellman-Ford或BFM)算法添加一个 队列 来实现优化。
尽管如此,SPFA的复杂度最劣情况仍旧是BFM算法的复杂度,毕竟本质上只是多了一个优化的操作。

BFM算法

要知道,Richard Bellman(理查德.贝尔曼)是 动态规划 的创始人。
而BFM算法,正是运用了动态规划的思想。
相较于采用贪心思想的Dijkstra算法的无法处理 负权边
动态规划显然没有这个限制。

松弛

那么状态是怎么转移的呢?
我们记从源点到每个节点i的距离为 dis[i](f[i])。(dis=distance 距离)

对于已知的当前节点i的的dis[i],记其要转移的下一个节点j,有边权w[i][j]。(w=weight 权值)

那么显然有 dis[j] = min( dis[i]+w[i][j] , dis[j] )

其实介个操作就叫 松弛 啦。

而且,当我们发现对于每个点都没法更优时,说明我们已经得到了最优解,
那么我们可以直接跳出,以优化时间。

初始化

由于我们需要的是最小值
那么除了源点本身,其余都应该初始化为 + 无穷大(INF)
而源点本身到自己的距离自然是0

时间复杂度

显然我们需要枚举除了终点的每个 i 和 j,
故其 时间复杂度 大概为 节点数N乘以边数M,即 O(NM)

SPFA

进行优化

我们说过了,我们可以对BFM算法加入一个队列来进行优化。

我们可以在松弛时,如果该点j可以使得当前路径更短,并且其不在队列中,再将其加入队列

因为,如果其已在队列中,我们对其再加入队列的访问是多余的
因为,如果后面可以继续使得路径更短,它就已经会被加入队列

所以,我们考虑加入一个 vis[i] 来表示其是否在队列中。(vis=visited 已访问)

所以对于该点,如果有负环,显然对其的访问次数会超过N(节点数)。

那么我们可以考虑加入一个count[i],统计每个点的访问次数,一旦超过N,说明该图存在负环。

显然,如果存在负环,那么最后最短路的结果会是负无穷。。。

于是乎,对于存在负环时,我们使函数返回 0

模板代码

SPFA

这里大概打一下,不保证你copy过去能过。
模板还是自己打最好啦,大佬们的代码比我更好,毕竟你大佬还是你大佬。

bool SPFA(int start) 当图存在负环时,我们返回 0
{
   
	memset
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值