SPFA 单源最短路算法 学习笔记
思想
SPFA 算法是对 Bellman-Ford 算法的优化。
我们令一张图中所有顶点的数量为
在 Bellman-Ford 算法中,我们需要对每一条边进行松弛操作,所以最终复杂度为
显然按照这种方法,可以处理含有负边权的图。
我们考虑到,在 Bellman-Ford 算法中,是否每一次松弛都使他们路径变短了,显然不是的。这就会导致浪费了许多的时间。
那么我们的 SPFA 算法正是对这一点进行了优化处理。
在 Bellman-Ford 算法中显而易见的问题是,有些松弛操作可能不会使路径变短。
那我们考虑,什么情况下一些点进行松弛操作路径会变短。
我们定义一个数组,
显然,若
那么我们只用考虑一个顶点
做法:
我们定义一个队列
除了刚才定义的
我们从起始点
接下来,我们每次取出队列的第一个顶点,对当前点的所有出边连接的点进行松弛,若松弛后路径变短,并且
我们重复进行该操作,直到所有顶点的
特性
显然,我们可以用 SPFA 处理含负边权的图。并且我们可以判断一个图是否存在负权回路(即一个所有边的边权和为负数的环)。
判断负权回路/负环做法:
根据 SPFA 的思想,每个点最多被其他
所以我们可以记录每个点入队的次数,若被某个点入队的次数大于等于
代码
令一张图中所有顶点的数量为
最坏时间复杂度
最坏情况即所有的边都需要进行松弛。
SPFA 的最坏时间复杂度达到了 Bellman-Ford 的平均复杂度。
优化还是很不错的,但是赛时确实容易被卡。
代码实现:
int dist[N];
queue<int>q;
bool vis[N];
void SPFA(){
memset(dist,0x3f,sizeof(dist));
dist[s] = 0;
q.push(s);
vis[s] = 1;
while (!q.empty()){
int tmp = q.front();
q.pop();
vis[tmp] = 0;
for (int i = head[tmp];i != 0;i = e[i].nxt){
int v = e[i].to;
int w = e[i].w;
if (dist[v] > dist[tmp] + w){
dist[v] = dist[tmp] + w;
if (!vis[v]){
q.push(v);
vis[v] = 1;
}
}
}
}
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 单线程的Redis速度为什么快?
· 展开说说关于C#中ORM框架的用法!
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· Pantheons:用 TypeScript 打造主流大模型对话的一站式集成库
· SQL Server 2025 AI相关能力初探