Bellman-Ford\SPFA单源最短路算法

Bellman-Ford单源最短路算法

不采用 SPFA 实现的Bellman-Ford算法

" 题目中的图没有特殊性质时,若 SPFA 是标算的一部分,题目不应当给出 Bellman–Ford 算法无法通过的数据范围 "


Bellman-Ford的原理如下

先枚举节点,在枚举边,每进行一轮循环,对图上所有的边都尝试进行一次松弛操作,当一次循环中没有成功的松弛操作时,退出循环

  • 判断负环的存在 (有\(n\) 个节点)

对于最短路存在的情况下,对这个节点进行一次松弛操作会使最短路的边数至少增加 \(1\) ,又因为图上的最短路的边数最多为 \(n-1\)

所以松弛操作最多只会执行 \(n-1\)

如果第 \(n\) 轮时我们还能对一条边进行松弛操作,说明能够到达一个负环,在这个环上没有最短路定义,可以一直松弛下去

struct edge {
int v, w; // 目标节点 v 和边权重 w
};
void init(void){
memset(dis,0x3f,sizeof dis);
}
bool bellman_ford(int s){
init();
dis[s]=0;
bool flag;
for (int i=1;i<=n;i++){//进行 n 轮
flag=0;
for (int u=1;u<=n;u++){//遍历所有节点
if (dis[u]==0x3f3f3f3f) continue;
for (auto it=e[u].begin();it!=e[u].end();it++){//遍历与u连通的边
if (dis[it->v]>dis[u]+it->w){//松弛操作
dis[it->v]=dis[u]+it->w;
flag=1;//标记这一轮可以松弛
}
}
}
if (!flag) break;//如果无法松弛,提前退出循环
}
return flag;//返回最后的标志,判断是否存在负环
}

其中,定义 flag 来判断是否能进行松弛操作,最后在第 \(n\) 轮时 flag 仍然为 \(1\) ,说明存在负环

if (dis[u]==0x3f3f3f3f) continue; 表示如果当前节点不能到达,那就跳过这个节点

  • 时间复杂度判断

对于每轮循环,内层的两个 for 都在干一件事情,那就是更新所有的边,所以一轮的复杂度就为 \(O(m)\),总的时间复杂度就为 \(O(nm)\)

优化方案——SPFA(Shortest Path Faster Algorithm)

朴素的算法中,我们会执行的不必要操作就是每轮都遍历所有的边

事实上,只有上一轮更新过的点才能引起这一轮的松弛操作,所以可以把上一轮更新的点记录下来,这一轮直接对这些点进行松弛操作

采用的是队列 queue 这一数据结构来维护更新的点

queue<int> q;

另外还需要cntvis 数组来记录当前节点最短路的边数以及是否在队中

bool vis[2010];
int cnt[2010];

SPFA:

bool spfa(int s) {
init();
dis[s] = 0;
q.push(s);
vis[s] = 1;
while (q.size())
{
int t = q.front(); q.pop();
vis[t] = 0;//取出队列
for (auto it = e[t].begin(); it != e[t].end(); it++) {
if (dis[it->v] > dis[t] + it->w) {
dis[it->v] = dis[t] + it->w;
cnt[it->v] = cnt[t] + 1;
if (cnt[it->v] >= n) return 1;//判断负环
if (!vis[it->v]) {//压入队列
q.push(it->v);
vis[it->v] = 1;
}
}
}
}
return 0;
}

首先将起点 s 压入队列,vis[s] = 1 表明在队中

  • 循环直到队列为空,即不能松弛结束
  • 根据最短路的边数来判断负环

如果一个点的最短路边数大于等于了节点数 n ,说明一定存在一个负环导致某些边的经过次数大于 \(1\) ,及时退出

如果当前的节点能够进行松弛操作,并且当前还不在队列中,就把他压入队列


大多数情况下 SPFA 跑得很快,但其最坏情况下的时间复杂度和朴素算法一样为 \(O(nm)\)

谨防卡 SPFA ,非负权图就用 Dijkstra

posted @   才瓯  阅读(10)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· AI技术革命,工作效率10个最佳AI工具
点击右上角即可分享
微信分享提示