bellman-ford算法网上介绍比较多,这里就不再复述,可参考https://blog.csdn.net/qq_40984919/article/details/80489441,或者搜索其他的博客文章。
原算法描述为:
BELLMAN-FORD(G, w, s)
n <- |V[G]|
p <- array[n]
d <- array[n]
for each v in V[G]
do d[v] <- ∞
p[v] <- NIL
d[s] <- 0
for i<-1 to n-1
do for each edge(u,v) in E[G]
do if d[v] > d[u]+w(u,v)
then d[v] <- d[u]+w(u,v)
p[v] <- u
for each edge(u,v) in E[G]
do if d[v] > d[u]+w(u,v)
then return FALSE
return TRUE
通过分析可以知道,是经过了n-1次松弛后判断是否达到最优来判断是否存在负权值回路,而最优的判断其实和松弛的判断是一样的。
因此对松弛操作添加一个标记,来记录是否达到最优,那么当不存在负权值回路的情况下,可能就不用遍历n次。重点标注下是可能不用遍历n次;对于离散的边或者排好序的边拥有比较好的收益,往往只需遍历较少的次数就能得到结果。
当然如果存在负权值回路,依然还是要遍历n次。
修改后的算法如下:
BELLMAN-FORD(G, w, s)
n <- |V[G]|
p <- array[n]
d <- array[n]
for each v in V[G]
do d[v] <- ∞
p[v] <- NIL
d[s] <- 0
for i<-1 to n-1
incomplete <- false
do for each edge(u,v) in E[G]
do if d[v] > d[u]+w(u,v)
then d[v] <- d[u]+w(u,v)
p[v] <- u
incomplete <- true
if not incomplete
then return TRUE
for each edge(u,v) in E[G]
do if d[v] > d[u]+w(u,v)
return FALSE
return TRUE
通过添加一个未完成标记判断是否修改过权值,如果出现了权值更小的路径,就标记为未完成;每对所有的边完成松弛完就判断是否有修改,一旦没有修改,后面即使循环再多次,也不可能还会修改,这样就能判断存在最短路径,可以立即返回。
当存在负权值回路时,就永远都会出现更小权值边,因此只需要保持和原算法一样的循环次数就行。