tasks for today:
1. bellman_ford 队列优化算法 (SPFA)94.城市间货物运输I
2. bellman_ford 之判断负权回路 95.城市间货物运输II
3. bellman_ford 单源有限最短路 96.城市间货物运输III
----------------------------------------------------------------------------
1. bellman_ford 队列优化算法 (SPFA)94.城市间货物运输I
This is a escalating version of the vanilla bellman_ford algorithm, which mainly concentrates on improving the efficiency through avoiding some repetative relaxation on some uncessary edge. The key idea is to use a que to store the node need to be relax, instead of traversing all the edge as in the vanilla bellman_ford algorithm.
from collections import defaultdict, deque
class Edge:
def __init__(self, to, value):
self.to = to
self.value = value
def main():
n, m = map(int, input().split())
grid = defaultdict(list)
for _ in range(m):
s, t, v = map(int, input().split())
grid[s].append(Edge(t, v))
minDis = [float('inf')] * (n+1)
start = 1
end = n
minDis[start] = 0
isInQueue = [False] * (n+1)
curQueue = deque()
curQueue.append(start)
isInQueue[start] = True
# for _ in range(n-1):
# update = False
# for edge in grid:
# fromNode = edge[0]
# toNode = edge[1]
# weight = edge[2]
# if minDis[fromNode] != float('inf') and minDis[toNode] > minDis[fromNode] + weight:
# minDis[toNode] = minDis[fromNode] + weight
# update = True
# if not update:
# break
# print(grid[curQueue.popleft()])
while curQueue:
curNode = curQueue.popleft()
isInQueue[curNode] = False
edges = grid[curNode]
for edge in edges:
fromNode = curNode
toNode = edge.to
weight = edge.value
if minDis[toNode] > minDis[fromNode] + weight:
minDis[toNode] = minDis[fromNode] + weight
if not isInQueue[toNode]:
curQueue.append(toNode)
isInQueue[toNode] = True
if minDis[end] == float('inf'):
print('unconnected')
else:
print(minDis[end])
return
if __name__ == "__main__":
main()
2. bellman_ford 之判断负权回路 95.城市间货物运输II
In this practice, the setting still allows the negative weights on the edge, which still focus on bellman_ford algorithm, but need some operation on checking if there is circle with negative sum in the graph, which makes the minimum solution does not exist.
For the case where there is no negative circle, after updating n-1 time, the minDis will not be updated anymore, whereas in the case where there is a negative circle, the minDis will keep being updated even after n-1 time. Therefore, as for the vanilla bellman_ford, it is eacy to do the modification to adapt to the case where there might be a negative circle, just do one more update after n-1 times, if the minDis is still changing, then there must be a negative circle in the case.
def main():
n, m = map(int, input().split())
grid = []
for _ in range(m):
s, t, v = map(int, input().split())
grid.append([s, t, v])
minDis = [float('inf')] * (n+1)
start = 1
end = n
minDis[start] = 0
for i in range(1, n+1):
update = False
ifNegCircle = False
for edge in grid:
fromNode = edge[0]
toNode = edge[1]
weight = edge[2]
if i < n:
if minDis[fromNode] != float('inf') and minDis[toNode] > minDis[fromNode] + weight:
minDis[toNode] = minDis[fromNode] + weight
update = True
else:
if minDis[fromNode] != float('inf') and minDis[toNode] > minDis[fromNode] + weight:
ifNegCircle = True
if not update:
break
if ifNegCircle:
print('circle')
elif minDis[end] == float('inf'):
print('unconnected')
else:
print(minDis[end])
return
if __name__ == "__main__":
main()
This practice can also be finished with the bellman_ford SPFA algorithm, the key is to following a rule which says, if one node is added into the curQueue more than n-1 times, that means there should be a negative circle in the graph. Therefore, this necessitates an additional list to monitor the times for each node to be added into the curQueue.
from collections import defaultdict, deque
class Edge:
def __init__(self, to, value):
self.to = to
self.value = value
def main():
n, m = map(int, input().split())
grid = defaultdict(list)
for _ in range(m):
s, t, v = map(int, input().split())
grid[s].append(Edge(t, v))
minDis = [float('inf')] * (n+1)
start = 1
end = n
minDis[start] = 0
isInQueue = [False] * (n+1)
count = [0] * (n+1)
curQueue = deque()
curQueue.append(start)
isInQueue[start] = True
count[start] += 1
ifNegCircle = False
while curQueue:
curNode = curQueue.popleft()
isInQueue[curNode] = False
edges = grid[curNode]
for edge in edges:
fromNode = curNode
toNode = edge.to
weight = edge.value
if minDis[toNode] > minDis[fromNode] + weight:
minDis[toNode] = minDis[fromNode] + weight
if not isInQueue[toNode]:
curQueue.append(toNode)
isInQueue[toNode] = True
count[toNode] += 1
if count[toNode] == n:
ifNegCircle = True
while curQueue: curQueue.popleft()
break
if ifNegCircle:
print('circle')
elif minDis[end] == float('inf'):
print('unconnected')
else:
print(minDis[end])
return
if __name__ == "__main__":
main()
3. bellman_ford 单源有限最短路 96.城市间货物运输III
In this practice, you should pay attention to then start and end point, while also the relaxation times for adhering to the requirement of k.
because the maximum points between the start and end is k, there would be maximum k+1 edges between these two points, which allows for k+1 times relaxation.
If we only do above modification on start, end and traverse time, the result would be wrong, becaue there would be negative circle showing up in the graph. This is resolved by add an additional list used to record the minDis in last step.
import copy
def main():
n, m = map(int, input().split())
grid = []
for _ in range(m):
s, t, v = map(int, input().split())
grid.append([s, t, v])
src, dst, k = map(int, input().split())
minDis = [float('inf')] * (n+1)
minDis[src] = 0
for _ in range(k+1):
minDis_copy = copy.deepcopy(minDis)
for edge in grid:
fromNode = edge[0]
toNode = edge[1]
weight = edge[2]
if minDis_copy[fromNode] != float('inf') and minDis[toNode] > minDis_copy[fromNode] + weight:
minDis[toNode] = minDis_copy[fromNode] + weight
if minDis[dst] == float('inf'):
print('unreachable')
else:
print(minDis[dst])
return
if __name__ == "__main__":
main()