-
Notifications
You must be signed in to change notification settings - Fork 32
/
Copy pathspfa求最短路.py
66 lines (53 loc) · 2.1 KB
/
spfa求最短路.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
# https://www.acwing.com/activity/content/problem/content/920/
# 请你求出 1 号点到 n 号点的最短距离,如果无法从 1 号点走到 n 号点,则输出 impossible。
# 边权可能为负数。
# spfa可以过很多dijk的题
# 但是网格的图容易卡spfa
# 有边数限制也能用spfa,spfa本质就是让bf不去枚举到不可能会拓展的边,bf能做的spfa都能
# 1. dist
# 2. queue
# 3. 判重数组 inQueue
from collections import deque
from typing import List, Optional, Tuple
INF = int(1e18)
def spfa1(n: int, adjList: List[List[Tuple[int, int]]], start: int) -> Optional[List[int]]:
"""spfa求单源最短路(图中有负边无负环,如果有负环则返回None)
适用于解决带有负权重的图,是Bellman-ford的常数优化版
"""
dist = [INF] * n
queue = deque([start])
inQueue = [False] * n
count = [0] * n
inQueue[start] = True
dist[start] = 0
count[start] = 1
while queue:
cur = queue.popleft()
inQueue[cur] = False
for next, weight in adjList[cur]:
cand = dist[cur] + weight
if cand < dist[next]: # 如果要最长路这里需要改成 >
dist[next] = cand
if not inQueue[next]:
count[next] += 1
if count[next] >= n:
return
inQueue[next] = True
if queue and dist[next] < dist[queue[0]]: # !酸辣粉优化 如果要最长路这里需要改成 >
queue.appendleft(next)
else:
queue.append(next)
return dist
if __name__ == "__main__":
# spfa 求最短路
n, m = map(int, input().split())
adjList = [[] for _ in range(n)]
for _ in range(m):
u, v, w = list(map(int, input().split()))
u, v = u - 1, v - 1
adjList[u].append((v, w))
dist = spfa1(n, adjList, 0)
if dist is None:
print("impossible")
exit(0)
print(dist[n - 1] if dist[n - 1] != INF else "impossible")