Dijkstra算法 python

10 篇文章 1 订阅
6 篇文章 0 订阅

单源最短路径

Dijkstra算法

Dijkstra算法解决的是带权重的有向图上单元最短路径问题,该算法要求所有边的权重都为非负值。

输入:有向图 G = ( V , E , W ) , V = { 1 , 2 , 3 , . . . , n } , s = 1 G=(V,E,W),V=\{1,2,3,...,n \},s=1 G=(V,E,W),V={1,2,3,...,n},s=1

输出:从s到每个顶点的最短路径

  1. 初始 S = { 1 } S=\{ 1\} S={1}.
  2. 对于 i ∈ V − S i \in V-S iVS, 计算 1 到 i i i 的相对 S S S 的最短路,长度 d i s t [ i ] dist[i] dist[i].
  3. 选择 V − S V-S VS d i s t dist dist 值最小的 j j j , 将 j j j 加入 S S S ,修改 V − S V-S VS 中顶点的 d i s t dist dist 值.

归纳证明思路

命题: 当算法进行到第 k k k 步时,对于 S S S 中每个结点 i i i ,
d i s t [ i ] = s h o r t [ i ] dist[i] = short[i] dist[i]=short[i]
归纳基础:
k = 1 , S = { s } , d i s t [ s ] = s h o r t [ s ] = 0 k=1,S=\{s\}, dist[s] = short[s] =0 k=1,S={s},dist[s]=short[s]=0
归纳步骤:

证明:假设命题对 k k k 为真, 则对 k + 1 k+1 k+1 命题也为真.

假设命题对 k k k 为真,考虑 k + 1 k+1 k+1 步算法,选择顶点 v v v (边 < u , v > <u,v> <u,v> ). 需要证明
d i s t [ v ] = s h o r t [ v ] dist[v] =short[v] dist[v]=short[v]
若存在另一条 s − v s-v sv 路径 L L L ,最后一次出 S S S 的顶点为 x x x ,经过 V − S V-S VS 的最后一个顶点 y y y ,再由 y y y 经过一段在 V − S V-S VS 中的路径到达 v v v .

在这里插入图片描述

k + 1 k+1 k+1 步算法选择顶点 v v v ,而不是 y y y , d i s t [ v ] ≤ d i s t [ y ] dist[v] \le dist[y] dist[v]dist[y]

y y y v v v 的路径长度为 d ( y , v ) d(y,v) d(y,v) , d i s t [ y ] + d ( y , v ) ≤ L dist[y]+d(y,v) \le L dist[y]+d(y,v)L

于是 d i s t [ v ] ≤ L dist[v] \le L dist[v]L, 即 d i s t [ v ] = s h o r t [ v ] dist[v]=short[v] dist[v]=short[v]

时间复杂度

  • 时间复杂度: O ( n m ) O(nm) O(nm)

  • 算法进行 n − 1 n-1 n1 步,每步挑选 1 个具有最小 d i s t dist dist 函数值的结点进入 S S S , 需要 O ( m ) O(m) O(m) 时间。

  • 选用基于堆实现的优先队列的数据结构,可以将算法时间复杂度降到 O ( m l o g n ) O(mlogn) O(mlogn)

例子

在这里插入图片描述

python实现

V = 9  # 顶点数
# dist[v] 标记数组
dist = [False for _ in range(V)]

# distance[i] 表示从源点s到i的最短距离
distance = [float('inf') for _ in range(V)]

# weight[u][v] 表示边E=(u,v)的权值
weight = [[float("inf") for _ in range(V)] for _ in range(V)]


def dijkstra(s):
    distance[s] = 0
    while True:
        v = -1
        for u in range(V):
            if not dist[u] and (v == -1 or distance[u] < distance[v]):
                v = u
        if v == -1:
            break

        dist[v] = True

        for u in range(V):
            distance[u] = min(distance[u], distance[v] + weight[v][u])


if __name__ == '__main__':
    Inf = float('inf')
    weight = [
        [0, 4, Inf, Inf, Inf, Inf, Inf, 8, Inf],
        [4, 0, 8, Inf, Inf, Inf, Inf, 11, Inf],
        [Inf, 8, 0, 7, Inf, 4, Inf, Inf, 2],
        [Inf, Inf, 7, 0, 9, 14, Inf, Inf, Inf],
        [Inf, Inf, Inf, 9, 0, 10, Inf, Inf, Inf],
        [Inf, Inf, 4, 14, 10, 0, 2, Inf, Inf],
        [Inf, Inf, Inf, Inf, Inf, 2, 0, 1, 6],
        [8, 11, Inf, Inf, Inf, Inf, 1, 0, 7],
        [Inf, Inf, 2, Inf, Inf, Inf, 6, 7, 0]
    ]
    a = int(input())
    dijkstra(a)
    print(distance)

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Gouzy_

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值