迪杰斯特拉Dijkstra算法-----关于最优路径的求解算法

文章介绍了使用Dijkstra算法寻找有向有权图中两点间最短路径的方法,通过递归更新节点的最短距离和父节点信息。在递归结束后,利用父节点回溯得到最短路径。代码示例中,输入为邻接矩阵,输出为最短路径长度及路线。注意输入不能包含负权值。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

       关于Dijkstra算法,有两个比较重要的点:

       第一是递归

       第二是父节点

       通过递归可以用比较少的代码量实现算法本体(就几行而已),同时在递归结束后使用父节点逆推即可实现路线的回溯。

       本代码逻辑为通过递归求得每一个节点离原点的最短路径长度,并使用父节点回推从而得到逆序路线,反转后即可输出。相关代码注释已标记

       详细的算法逻辑参考其他解说和视频,以下代码是整个功能的实现,仅供参考,有任何问题欢迎评论和指正!

       (注意:

       输入为邻接矩阵(有向有权图),不可输入负权值,按步骤输入,不可非正常输入。

       输出为最短路径长度以及最短路线。

import numpy as np

# ##########获取图、设置图########## #
n = int(input("输入点的个数:"))  # 获取图的点个数
adjacent = np.zeros((n, n))  # 预生成一个长和宽为n,名为adjacent的邻接矩阵
best_result = np.zeros((n, n))  # 预生成一个长和宽为n,表示最优解路径的邻接矩阵
close = np.full(n, 999999)  # 预生成一个存储每个节点到原点的最近距离的数组,原点默认距离为0
father = np.full(n, -1)  # 预生成一个存储每个节点的父节点的数组,原点的父节点默认为-1

# ##########设置邻接矩阵########## #
print("输入邻接矩阵,一个回车输入一个数字,到自身距离为0,没有直接连接距离也为0!")  # 自定义输入邻接矩阵
for i in range(n):
    for j in range(n):
        adjacent[i][j] = int(input("第" + str(i + 1) + "行第" + str(j + 1) + "个数:"))

# adjacent = [[0, 2, 0, 9, 6, 0, 0, 0, 0],  # 备用邻接矩阵
#            [0, 0, 1, 0, 3, 0, 0, 0, 0],
#            [0, 0, 0, 0, 1, 0, 6, 0, 0],
#            [0, 0, 0, 0, 0, 0, 0, 4, 0],
#            [0, 0, 0, 2, 0, 9, 0, 7, 0],
#            [0, 0, 0, 0, 0, 0, 5, 0, 1],
#            [0, 0, 0, 0, 0, 0, 0, 0, 5],
#            [0, 0, 0, 0, 0, 1, 0, 0, 5],
#            [0, 0, 0, 0, 0, 0, 0, 0, 0]]

# ##########设置最短距离数组########## #
start = int(input("输入出发点的序号:")) - 1  # 从数组序号为start的起始点开始寻找最优路径(数组序号比图序号小1)
stop = int(input("输入目的点的序号:")) - 1  # 以finish为路径终点
close[start] = 0  # 原点到原点的距离为0

# ##########dijkstra算法本体########## #


def dijkstra_recursion(start1):  # 运行一次函数完成一个点周围的点的最短路径运算,如果没有最短路径更新,不会触发下一次递归

    for k in range(n):
        if close[start1] + adjacent[start1][k] < close[k] and adjacent[start1][k] != 0:  # 存在点k能连接到点start1且能使得最短距离更短
            close[k] = close[start1] + adjacent[start1][k]  # 更新原点经过点start1到点k的最短距离
            father[k] = start1  # 更新点k的父节点为start1
            start1 = k  # 让点k变为下一次递归的起始点
            dijkstra_recursion(start1)  # 让点k继续递归


# ##########处理算法执行结果########## #
dijkstra_recursion(start)  # 从起始点start开始递归

if close[stop] == 999999:  # 如果起始点没法到达目的点(即目的点到起始点距离为999999没变)
    print("该起始点无法到达目的点!")
elif start == stop:
    print("起始点与目的点重合!")  # 如果起始点与目的点重合(不考虑自环,因为会增加路径长度)
else:
    print("\n路径长度为:", close[stop])
    route = np.full(n, -1)  # 用来存储通过父节点得出的路线
    for i in range(n):
        route[n - i - 1] = stop  # 路线数组的最后一个位置是目的点
        stop = father[stop]  # 将stop变为改点的父节点,继续往回推
        if father[stop] == -1:  # 如果下一个点的父节点是-1,那么当前就已经到出发点了,退出循环
            break

    print("最优路径为:\n", start + 1, end="")  # 从原点开始输出路径,不换行
    for i in range(n):
        if route[i] != -1:  # 循环至原点开始输出(不包含原点),不换行
            print("->", route[i] + 1, end="")

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值