Spfa算法总结(C/C++)

article/2025/10/23 13:00:59

文章目录

    • 一: Spfa算法分析
    • 二: 代码分析

一: Spfa算法分析

1. 问题介绍
在这里插入图片描述


2. 问题分析
 当我们遇到单源最短路+边权为负值问题时这时候该如何处理呢?
 其实我们现在就可以使用Floyd()算法了,我们可以从两个方面来理解这个算法.
 第一个方面从Bellman_ford()算法来理解,Spfa算法其实就是对Bellman-ford算法的一个优化,因为Bellman_ford算法每次其实都是对所有边的一个松弛过程,但其实我们可以优化为只去松弛那些距离变小的点并将其放入队列当中继续松弛即可。
 其实有一个更好理解的方式,Spfa算法其实就和Dijkstra算法类似,不过的是Dijkstra算法每次都可以确定一个最优解,而Spfa无法确定,所以Spfa可以就看作从一个点开始让整个图不断优化,可以优化就又从那个点开始继续优化直至优化到这个图内所有点都无法再去优化其他点(即所有点达到最优解)。
 负环判断:先让所有点都进入队列(相当于引入一个虚拟点到所有点),然后同时从所有点开始去走,同时记录走到当前点所经过得边数,当边数 >= n结点数量的时候,我们就可以确认必定出现负环,因为经过了n个结点则代表一定经过了n + 1条边.


3. 算法细节对比:
  a.相同点:算法格式和Dijkstra算法类似
  b.不同点:
  Dijkstra算法使用优先队列, Spfa使用一般队列即可。
  Dijkstra算法每次选取出来的值即是最优解,其状态st[ ] 表示是否已经选取,且状态不可逆 false 变为 true 不可倒退。
  Spfa算法因为可能此点会被其他点再次优化所以其 状态st[ ]表示的是是否进入队列当中,可能会再次出队列所以要同步更新st[ ] 状态。



4. 算法总结:
 时间复杂度: 最优 O(m) ,最差退回bellman-ford O(n m)
 处理问题: 单源最短路 + 权值为负

二: 代码分析

a.注意时刻保持st[ ]状态和点是否在队列当中一致

	// 出队列int u = q.front();q.pop();// 进队列st[u] = false;q.push(j);st[j] = true;

b.可以利用cnt[ ]数组记录离源点边数,当边数>=n 证明存在负环

for(int i = h[u]; ~ i; i = ne[i] ){int j = e[i];if(dis[j] > dis[u] + w[i] ){dis[j] = dis[u] + w[i];cnt[j] = cnt[u] + 1;if (cnt[j] >= n) puts("存在负环")if(!st[j]){q.push(j);st[j] = true;}}
}

c.完整代码

#include<iostream>
#include<cstring>
#include<algorithm>
#include<queue>
using namespace std;
const int N = 1e5 + 10, inf = 0x3f3f3f3f;
int h[N], e[N], ne[N], w[N], idx = 0;
int n, m, dis[N];
bool st[N];
void add(int x, int y, int z){e[idx] = y, ne[idx] = h[x], w[idx] = z, h[x] = idx ++;
}
void spfa(){queue<int> q;q.push(1);dis[1] = 0;st[1] = true;/* 判断整个图是否有负环,先全部入队列for(int i = 1; i <= n; i ++ ){q.push(i);st[i] = true;}*/while(!q.empty() ){//先初始化放入初始源点int u = q.front();q.pop();st[u] = false;//将此点优化过的点再次放入队列,重复这个过程直至队列为空即可for(int i = h[u]; ~ i; i = ne[i] ){int j = e[i];if(dis[j] > dis[u] + w[i] ){dis[j] = dis[u] + w[i];// cnt[j] = cnt[u] + 1;// if (cnt[j] >= n) puts("存在负环")if(!st[j]){q.push(j);st[j] = true;}}}}}int main(){memset(h, -1, sizeof(h) );memset(dis, 0x3f, sizeof(dis) );cin >> n >> m;for(int i =0; i < m; i ++ ){int x, y, z;cin >> x >> y >>z;add(x, y, z);}spfa();if(dis[n] == inf) puts("impossible");else cout << dis[n] << endl;
}

http://chatgpt.dhexx.cn/article/PvGaDKb6.shtml

相关文章

第十八章 SPFA算法以及负环问题(利用dijkstra推导出该算法,超级详细!!)

第十八章 SPFA算法以及负环问题 一、dijkstra算法的弊端二、dijkstra算法的优化1、SPFA算法&#xff08;1&#xff09;算法思路&#xff1a;&#xff08;2&#xff09;算法模板&#xff1a;问题&#xff1a;模板&#xff1a;逐行分析&#xff1a; 三、SFPA解决负环问题&#xf…

SPFA算法理论体系终极论证

SPFA相关详细论证 历史事件Bellman-Ford算法简述和证明SPFA的正确代码段凡丁的贡献正确复杂度分析 历史事件 众所周知&#xff0c;SPFA是一种对Bellman-Ford算法的优化。国内业界首次提出是1994年西南交通大学的段凡丁在学报上发表的论文。但实际上早在1956年Bellman-Ford算法…

spfa判定负环

算法思想&#xff1a; 我们用数组记录每个结点的最短路径估计值&#xff0c;用邻接表来存储图G。 采取的方法是动态逼近法&#xff1a; 1、设立一个先进先出的队列用来保存待优化的结点。 2、优化时每次取出队首结点u&#xff0c;并且用u点当前的最短路径估计值对离开u点所指向…

SPFA算法详解——判断负权环

算法核心代码实现负权环判断负权环 根据松弛次数根据最短路径上的死循环 SPFA&#xff08;Shortest Path Faster Algorithm&#xff09;&#xff08;队列优化&#xff09;算法是求单源最短路径的一种算法。它是在Bellman-ford算法的基础上加上一个队列优化&#xff0c;减少了冗…

(算法基础)SPFA算法

适用情景 SPFA算法一般运用在求最短路问题当中的单源最短路中存在负权边的情况&#xff08;正权边如果出题人没有特别恶心去卡的话&#xff0c;也是ok的&#xff09;&#xff0c;SPFA算法还可以去判断图中是否存在负环。 时间复杂度 一般来讲是O(m)&#xff0c;m就是图当中的边…

透析SPFA算法(图例讲解)

SPFA算法是Bellman-Ford的队列优化&#xff0c;所以先介绍Bellman-Ford算法。 Dijkstra算法是处理单源最短路径的有效算法&#xff0c;但它局限于边的权值非负的情况&#xff0c;若图中出现权值为负的边&#xff0c;Dijkstra算法就会失效&#xff0c;求出的最短路径就可能是错的…

SPFA 算法详解( 强大图解,不会都难!)

适用范围&#xff1a;给定的图存在负权边&#xff0c;这时类似Dijkstra等算法便没有了用武之地&#xff0c;而Bellman-Ford算法的复杂度又过高&#xff0c;SPFA算法便派上用场了。 我们约定有向加权图G不存在负权回路&#xff0c;即最短路径一定存在。当然&#xff0c;我们可以…

OSPF NSSA区域路由的计算过程与FA值实验

概述&#xff1a; NSSA区域中不存在5类LSA&#xff0c;但是为了描述区域外的路由条目&#xff0c;则用7类LSA代替5类LSA。 7类LSA仅在NSSA区域中存在&#xff0c;当7类LSA离开NSSA区域进入普通区域时&#xff0c;可以转化为5类LSA。 NSSA-LSA报文格式和5类LSA相同&#xff1…

求不规则立方体表面积java_不规则立方体体积计算

展开全部 计算不规则的立体图形体积可62616964757a686964616fe78988e69d8331333431373866以把这个物体放入水中&#xff0c;用现在容积-未放入物体的容积就是体积或用放入物体后高-未放入物体*长*宽(1升1立方分米&#xff1b;1毫升1立方厘米)。 体积的国际单位制是立方米。一件…

冠层分析法(VCP)提取叶面积指数

文章目录 一、简介二、代码实现三、小结参考文献一、简介 该方法最早是由Omasa等人提出,是根据激光雷达光束与树木的接触频率来计算光束截获概率。总结来讲具体过程分为三步: 1、 从三维体素模型网格里判断是否有点,有点的网格标记为1,没点的网格标记为0,没点的网格表明冠…

SPFA例题

引入 SPFA的核心思想是优化dist[a]min(dist[a],dist[b]w)这个式子&#xff1b; 不难想到&#xff0c;如果我们想要优化dist[a]&#xff0c;那么只能从dist[b]w这个式子转移过来&#xff1b; 也就是说&#xff0c;只有dist[b]变小了&#xff0c;才有可能优化dist[a]&#xff…

OSPF中的SPF计算

OSPF域内路由计算&#xff1a;SPF计算 在1类LSA和2类LSA中&#xff0c;包括了拓扑信息和路由信息 Phase 1 &#xff1a;根据1类LSA中的P2P、TransNet、2类LSA&#xff0c;构建SPF树 Phase 2&#xff1a;根据1类LSA中的Stub、2类LSA&#xff0c;计算最优路由 左边是拓扑图&am…

聊一聊有限体积法

导读&#xff1a;有限体积法的工作原理。 一、求解对象 首先提一下我们的主角Navier-Stokes方程&#xff1a; 为了能够通过SIMPLE算法求解Navier-Stokes方程&#xff0c;我们需要将该方程改写为下列矩阵形式的方程&#xff1a; 其中为了系数矩阵&#xff0c;是每个网格未知…

IDEA中新导入的项目找不到maven project解决办法

刚导入的项目&#xff0c;导入进来之后&#xff0c;找不到maven project&#xff0c;idea打开view ->tool windows下也没有maven模块。查看了setting下plugins中maven插件也在。最后发现项目在导入过程中&#xff0c;因为选择的原因&#xff0c;没有指定位maven工程&#xf…

win10删除文件提示'找不到该项目'

win10系统下删除文件时出现了"找不到该项目"问题 遇到一个问题: win10系统下删除文件时出现了"找不到该项目"问题 百度搜索后得到 DEL /F /A /Q \\?\%1 RD /S /Q \\?\%1 这两行dos命令 创建(.txt)文件后写入这两行命令,保存,修改(.txt)至(.bat) 最后…

IDEA项目下不显示target目录或者target目录不完整没有新添加的资源

1.首先解决不显示target目录的问题 需要知道:如果不是maven工程,是没有target目录的,其次编译后才会生成target目录. 普通项目会生成out目录 a>如果设置过隐藏target目录 只需要找到settings-->Editor-->File Type-->Ignore Files and Folder删除该项 b>如果…

项目启动报错,找不到文件

java.io.FileNotFoundExceptionE:\software\apache-maven-3.6.1-bin\apache-maven-3.6.1\localrepository\xalan\xalan\2.7.0\xercesImpl.jar (系统找不到指定的文件。) java.io.FileNotFoundExceptionE:\software\apache-maven-3.6.1-bin\apache-maven-3.6.1\localrepository\…

idea项目类存在却找不到

这种情况&#xff0c;我真是奇了怪了&#xff0c;服了。我试了一下&#xff0c;试出了解决方案&#xff1a;将这个类移到同级另一个包&#xff0c;看见不报错了&#xff0c;再移回去。属于给idea虚晃一枪&#xff0c;再运行…emmmmm也还是报错的。于是不断的删iml文件&#xff…

Windows 删除”找不到该项目”文件夹

问题根源&#xff1a; 使用不可显示ASCII字符或采用UNICODE字符方法创建的文件或文件夹&#xff1b; 名称中含有..等特殊符号文件或文件夹名称不符合Windows命名规范或建立空格目录名创建的文件或文件夹&#xff1b; 使用下载工具创建的文件夹,在未下载完成前自行删除文件或…

idea找不到项目目录

有时候idea拉取项目时出现没有目录&#xff0c;src.main等等&#xff0c;下面就来带大家找到项目目录并显示出来 首先我们打开文件&#xff08;在左上角——找到项目结构&#xff09; 然后我们找到模块——点击左边那个加号,然后选择自己的项目目录。再选择一下jdk版本&#x…