代码随想录算法训练营第61天|Bellman_ford 队列优化算法(又名SPFA)、bellman_ford之判断负权回路、bellman_ford之单源有限最短路

1.Bellman_ford 队列优化算法(又名SPFA)

题目链接:Bellman_ford 队列优化算法(又名SPFA)
文档讲解: 代码随想录

Bellman_ford算法每次都对所有边进行松弛,但其实真正有效的松弛,是基于已经计算过的节点在做的松弛。使用队列来优化,只对上一次松弛更新过的节点作为出发点作为出发节点所连接的边进行松弛就可以了。在加入队列的过程可以有一个优化,用visited数组记录已经在队列里的元素,已经在队列的元素不用重复加入。

from collections import defaultdict,deque
#定义节点指向和权值
class Edge:
    def __init__(self,to,val):
        self.to = to 
        self.val = val 
n,m = map(int,input().split())
edges = defaultdict(list)
for _ in range(m):
    p1,p2,val = map(int,input().split())
    edges[p1].append(Edge(p2,val))
#记录的是否在队列里
isque = [False] * (n+1)
start = 1 
end = n 
minDist = [float('inf')] * (n+1)
minDist[start] = 0 
que = deque()
que.append(start)
while que:
    cur = que.popleft() 
    #从队列里取出要取消标记
    isque[cur] = False
    for edge in edges[cur]:
        to = edge.to 
        val = edge.val 
        #松弛
        if minDist[cur] + val < minDist[to]:
            minDist[to] = minDist[cur] + val 
            if isque[to] == False:
                que.append(to)
                isque[to] = True 
if minDist[end] == float('inf'):
    print("unconnected")
else:
    print(minDist[end])

图越稀疏,SPFA的效率就越高。一般来说,SPFA的时间复杂度为 O ( K ∗ N ) O(K*N) O(KN),K为不定值,因为节点需要计入几次队列取决于图的稠密度。如果存在正权环路,即使元素重复加入队列,最后也会因为所有边都松弛后,节点数量(minDist数组)不再发生变化而终止。

2.bellman_ford之判断负权回路

题目链接:bellman_ford之判断负权回路
文档讲解: 代码随想录

这道题和上一题的区别在于存在负权环路,在bellman_ford算法中,对于minDist数组,松弛n-1次所有边就可以得到起点到其他节点的最短距离,松弛n次以上,数组中的结果也不会改变。而如果存在负权环路,一直会有更短的最短路,所以松弛第n次,minDIst数组也会发生改变。那么本题判断是否存在负权环路的核心在于,松弛第n次,看minDist数组是否发生变化。

n,m = map(int,input().split())
grid = []
for _ in range(m):
    grid.append(list(map(int,input().split())))
start = 1 
end = n 
minDist = [float('inf')] * (n+1)
minDist[start] = 0 
flag = False
for i in range(n+1):
    for p1,p2,val in grid:
        if i < n:
            if minDist[p1] != float('inf') and minDist[p1] + val < minDist[p2]:
                minDist[p2] = minDist[p1] + val 
        else:
            if minDist[p1] != float('inf') and minDist[p1] + val < minDist[p2]:
                flag = True 
if flag:
    print("circle")
elif minDist[end] == float('inf'):
    print("unconnected")
else:
    print(minDist[end])

3.bellman_ford之单源有限最短路

题目链接:bellman_ford之单源有限最短路
文档讲解: 代码随想录

本题为单源有限最短路问题, 最多经过k个城市,那么是k+1条边相连的节点。对所有边松弛k+1次,就是求起到到达与起点k+1条边相连的节点的最短距离。在对所有边进行松弛的过程中,有可能因为边的顺序导致所有节点都更新,这就可能违背至多经过k个节点的限制。所以在每次计算minDist数组时,要基于对所有边上一次松弛的minDist数值才行。

n,m = map(int,input().split())
grid = []
for _ in range(m):
    grid.append(list(map(int,input().split())))
src,dst,k = map(int,input().split())
minDist = [float('inf')] * (n+1)
minDist[src] = 0
for _ in range(k+1):
    minDist_copy = minDist[:]
    for s,t,v in grid:
        if minDist_copy != float('inf') and minDist_copy[s] + v < minDist[t]:
            minDist[t] = minDist_copy[s] + v 
if minDist[dst] == float('inf'):
    print("unreachable")
else:
    print(minDist[dst])
  • 4
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值