首先,三者都是用来求最短路,但是思想和复杂度不相同。
bellman-ford 和spfa的区别
1.Bellman-ford算法中,循环n次,每次遍历m条边,每次遍历的时候,把入度的点的距离更新成最小。
然而,这样就循环遍历了很多用不到的边。比如第一次遍历,只有第一个点的临边是有效的。
2.因此,spfa算法中,采用邻接表的方式,只用到有效的点(更新了临边的点),直到每个点都是最短距离为止。采用队列优化的方式存储每次更新了的点,每条边最多遍历一次。如果存在负权回路,从起点1出发,回到1距离会变小, 会一直在三个点中循环。
$\cal{Question:}$ 不用队列,遍历所有的点可以吗?
$\cal{Ans:}$似乎不行,因为是更新了点之后,这个点的临边才可以用,如果没有更新到循环的点,那么循环的点也是不可用的。
spfa和dijkstra的区别:
st用来检验队列中是否有重复的点
spfa从队列中使用了当前的点,会把该点pop掉,状态数组st[i] = false(说明堆中不存在了) ,更新临边之后,把临边放入队列中, 并且设置状态数组为true,表示放入队列中 。如果当前的点距离变小,可能会再次进入队列,因此可以检验负环:
每次更新可以记录一次,如果记录的次数 > n,代表存在负环(环一定是负的,因为只有负环才会不断循环下去)。
st是一个集合,不是检验队列中的点。
dijkstra使用当前点更新临边之后,把该点加入到一个集合中,使用该点更新临边,并把临边节点和距离起点的距离置入堆中(不设置状态数组)。下一次从堆中取最小值,并把对应的节点放入集合中,继续更新临边节点,直到所有的点都存入集合中。因此dijkstra不判断负环。
从上述描述中能看出,dijkstra存放节点的堆,具有单调性,而spfa的队列不需要具有单调性。
写的真好,dijkstra是基于贪心的思想,每次选择最近的点去更新其它点,过后就不再访问。而在spfa算法中,只要有某个点的距离被更新了,就把它加到队列中,去更新其它点,所有每个点有被重复加入队列的可能。
哈哈哈,我很赞同你的看法,今天我复习了一遍,在你这里插个眼,以后复习的话,来这里看你的这句话可能就想起来思路了
谢谢大佬 很有启发
总结的到位,茅塞顿开
同插眼
插个眼
插个眼!!
插个眼
cy
cy
$cy$
cy
st是一个集合,不是检验队列中的点 这句话啥意思?我感觉就是看一下队列里有没有用过呀?求大佬指教
我也不太懂st数组的含义,而且st数组为什么可以从false变回true
还是因为负边的存在吧,你可以这么想,从A到B有一条权值为100的单向边,但从A到C有一条权值为200的单向边,从C到B有一条权值为-300的单向边,如果B第出队后state值就不再变回true的话,那么后续A->C->B这条路径就无法再更新dist[B]了。
其实说白了就是因为有负权边的存在,所以某点的dist无法像djkstra那样逐步贪心得出。
🐂的,感谢解释,我自己再好好想一想
tql
感谢!
代码呢
可能只提供思路不提供代码hh
感谢!%%%
作者解释得真好,顶一个^v^~~
666