浅谈 SPFA 的堆优化

我下午在做最短路时想到了 SPFA 可以使用堆优化来做,并且经过实践我得出了它确实有效。

之后我上网搜索,网络上很少有过关于 SPFA 堆优化的论述,就算有也讲的不太清楚,因此此文章就来回答一下三个问题,如有错误,欢迎私信。

问:它的运行时间是否在遇到大部分数据时都小于等于普通的 SPFA ?

答:它的运行时间在正权图上等价于 Dijkstra 算法,但在负权图上可以被卡到指数级的复杂度

问:它和 Dijkstra 一样吗?

答:它和 Dijkstra 不一样。应为它支持一个点重复入堆,而 Dijkstra 遍历到某结点时必须判断该结点有没有被统计过,若被统计过应当直接跳过。

问:它能否继承普通 SPFA 的特点,如判断负环和处理负权图?

答:能。堆优化的 SPFA 能够继承普通 SPFA 处理负权图的能力,并且同样能够检测负权环。这是因为它在松弛过程中保留了 Bellman-Ford 算法的核心特性:对每个顶点进行最多 n−1n-1n1 次松弛操作(其中 nnn 是顶点数)。如果某个顶点在算法结束时仍然可以被松弛,或者某个顶点被松弛的次数超过了 n−1n-1n1 次,那么图中就存在负权环。需要注意的是,它在处理某些负权图上可以被卡到指数级的复杂度。

总结

SPFA 的堆优化在正权图上完全可以被 Dijkstra 算法所替代,而在负权图的复杂度也是不如普通的 SPFA 的。在选择最短路径算法时,你仍然需要根据问题的具体要求和图的特性来做出明智的决策。

参考代码

#include<bits/stdc++.h>
#define int long long
using namespace std;
int n,m,d,h[500005],ans[100005],js;
struct edge{
	int n,v,w;
}a[500005];
struct node{
	int id,w;
	bool operator<(const node &a)const{
		return w>a.w;
	}
};
void add(int u,int v,int w){
	a[++js].n=h[u];
	a[js].v=v;
	a[js].w=w;
	h[u]=js;
}
void spfa(int d){
	priority_queue<node> q;
	memset(ans,0x3f3f3f3f3f,sizeof ans);
	ans[d]=0;
	q.push(node{d,0});
	while(q.empty()==0){
		node f=q.top();
		q.pop();
} 
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值