1.dijkstra(堆优化版)精讲
题目链接:dijkstra(堆优化版)精讲
文档讲解: 代码随想录
与朴素版dijkstra区别在于,邻接表的表达方式不同,使用优先级队列(小顶堆)来对新连接的边排序。
dijkstra算法的三部曲:第一步,选距离源点最近的节点且未被访问过;第二步,该节点被标记访问过;第三步,更新minDist数组。当从边的角度 出发,在处理第一步的时候就不需要遍历所有节点,而且直接把边加入到小顶堆中,那么每次从堆顶中取到的边自然就是距离源点最近的节点所在的边。
import heapq
#定义类:记录节点的指向和权值
class Edge:
def __init__(self,to,val):
self.to = to
self.val = val
def dijkstra(n,edges,start,end):
#新建列表
grid = [[] for _ in range(n+1)]
#构建邻接表
for p1,p2,val in edges:
grid[p1].append(Edge(p2,val))
minDist = [float('inf')] * (n+1)
visited = [False] * (n+1)
#初始化
minDist[start] = 0
#新建优先级队列
pq = []
heapq.heappush(pq,(0,start))
while pq:
#选择距离源点最近的节点
cur_dist,cur_node = heapq.heappop(pq)
#判断是否访问过
if visited[cur_node]:
continue
#标记节点被访问过
visited[cur_node] = True
#更新距离
for edge in grid[cur_node]:
if not visited[edge.to] and cur_dist + edge.val < minDist[edge.to]:
minDist[edge.to] = cur_dist + edge.val
heapq.heappush(pq,(minDist[edge.to],edge.to))
if minDist[end] == float('inf'):
return -1
else:
return minDist[end]
n,m = map(int,input().split())
edges = []
for _ in range(m):
edges.append(list(map(int,input().split())))
res = dijkstra(n,edges,1,n)
print(res)
堆优化的时间复杂度为 O ( E l o g E ) O(ElogE) O(ElogE),E是边的数量。从边的角度考虑,所以时间复杂度只与边有关。跳出局部代码,整个队列一定是所有边添加一次复杂度为 O ( E ) O(E) O(E),同时也弹出一次复杂度为 O ( l o g E ) O(logE) O(logE),因此整体时间复杂度为 O ( E l o g E ) O(ElogE) O(ElogE)。空间复杂度为 O ( N + E ) O(N+E) O(N+E),建立邻接表,数组空间为N,有多少条边就对应多少的链表节点。
2.Bellman_ford 算法精讲
题目链接:Bellman_ford 算法精讲
文档讲解: 代码随想录
这道题和之前题目不同的地方在于边的权值是有负数的。Bellman_ford算法的核心是对所有边进行松弛n-1次操作,n是节点数量,从而求得目标最短路。对所有边松弛一次,相当于计算起点到达与起点一条边相连的节点的最短距离。松弛两边则相当于计算起点到达与起点两条边相连的节点的最短距离。以此类推,节点数量为n,起点到终点最多有n-1条边,因此需要松弛n-1次。
n,m = map(int,input().split())
grid = []
for _ in range(m):
grid.append(list(map(int,input().split())))
minDist = [float('inf')] * (n+1)
start = 1
end = n
minDist[start] = 0
#n-1次松弛
for _ in range(1,n):
#对所有边松弛
for p1,p2,val in grid:
if minDist[p1] != float('inf') and minDist[p1] + val < minDist[p2]:
minDist[p2] = minDist[p1] + val
if minDist[end] == float('inf'):
print("unconnected")
else:
print(minDist[end])
但是python运行超时。时间复杂度为 O ( N ∗ E ) O(N*E) O(N∗E),N是节点数量,E是边的数量。空间复杂度为 O ( N ) O(N) O(N),grid数组是用来存图的,是题目描述中必须要使用的空间,而不是算法使用的空间,因此只算minDist数组的空间。