【算法基础】Dijkstra 算法

发布于:2024-07-20 ⋅ 阅读:(84) ⋅ 点赞:(0)

定义:

  • g [ i ] [ j ] g[i][j] g[i][j] 表示 v i v_i vi 到 $v_j $的边权重,如果没有连接,则 g [ i ] [ j ] = ∞ g[i][j] = \infty g[i][j]=
  • d i s [ i ] dis[i] dis[i] 表示 v k v_k vk 到节点 v i v_i vi 的最短长度, d i s [ k ] = 0 , d i s [ i ] = ∞ , i ≠ k dis[k] = 0, dis[i]=\infty, i \neq k dis[k]=0,dis[i]=,i=k.

目标:

  • 计算出 d i s dis dis 数组,也就是任何点到 v k v_k vk 的距离。

step1 : 更新 v k v_k vk 的所有邻居节点 v y v_y vy的最短路径; 即: d i s [ y ] = g [ k ] [ y ] dis[y] = g[k][y] dis[y]=g[k][y]
step2 : 找出 这些邻居节点中路径最短的 d i s [ i 1 ] dis[i1] dis[i1]. 此时 d i s [ i 1 ] dis[i1] dis[i1] 一定已经是最短的了,可以用反证法来证明。
step3 : 找出 v i 1 v_{i1} vi1 的邻居节点 y ′ y' y, 如果 d i s [ i 1 ] + g [ i 1 ] [ y ′ ] < d i s [ y ′ ] dis[i1]+g[i1][y'] < dis[y'] dis[i1]+g[i1][y]<dis[y], 则更新 d i s [ y ′ ] = d i s [ i 1 ] + g [ i 1 ] [ y ′ ] dis[y'] =dis[i1]+g[i1][y'] dis[y]=dis[i1]+g[i1][y], 否则不更新。
step4 : 找出 k , i 1 k,i1 k,i1之外的 d i s [ i ] dis[i] dis[i] 最小的值 d i s [ i 2 ] dis[i2] dis[i2], 重复之前的更新过程,知道取完所有点为止。

code :

leecode 743
朴素写法:

class Solution:
    def networkDelayTime(self, times: List[List[int]], n: int, k: int) -> int:
        g = [[inf for _ in range(n)] for _ in range(n)]  # 邻接矩阵
        for x, y, d in times:
            g[x - 1][y - 1] = d

        dis = [inf] * n
        ans = dis[k - 1] = 0  # 起始节点
        done = [False] * n   #是否确定为最短
        while True:
            x = -1
            # 找到最短的 done 是用来排除已经确定的那些点的。完成后x 记录当前最短距离的那个点。
            # 起始为 k
            for i, ok in enumerate(done):
                if not ok and (x < 0 or dis[i] < dis[x]):
                    x = i
            # 没有找到,也就是所有点已经全部确定后。
            if x < 0:
                return ans  # 最后一次算出的最短路就是最大的
            # 无法到达
            if dis[x] == inf:  # 有节点无法到达
                return -1
            # 因为每次都是递增的,而答案是要求最大的最短路径。
            ans = dis[x]  # 求出的最短路会越来越大
            done[x] = True  # 最短路长度已确定(无法变得更小)
            # 更新 x 的邻居节点的最短距离。
            for y, d in enumerate(g[x]):
                # 更新 x 的邻居的最短路
                dis[y] = min(dis[y], dis[x] + d)

堆优化 Dijkstra:

class Solution:
    def networkDelayTime(self, times: List[List[int]], n: int, k: int) -> int:
        g = [[] for _ in range(n)]  # 邻接表
        for x, y, d in times:
            g[x - 1].append((y - 1, d))

        dis = [inf] * n
        dis[k - 1] = 0
        h = [(0, k - 1)]   # 二元组 (dis[i], i)
        while h:
            dx, x = heappop(h)  # 找到最短路径的 x 和其相应的 dis
            if dx > dis[x]:  # x 之前出堆过,
                continue
			# 这里continue 是因为 对于一个x 由于更新了多次dis, 堆中科恩那个存在多个 dx, 对于那些较大的dx, 不再使用的意思。
            # 更新邻居
            for y, d in g[x]:
                new_dis = dx + d
                if new_dis < dis[y]:
                    dis[y] = new_dis  # 更新 x 的邻居的最短路
                    heappush(h, (new_dis, y))
        mx = max(dis)
        return mx if mx < inf else -1


网站公告

今日签到

点亮在社区的每一天
去签到