单元最短路径(贪心算法)

本文详细介绍了Dijkstra算法的工作原理,如何通过非负权重的有向图解决最短路径问题,并提供了Python实现的代码示例。通过输入顶点数量和边权矩阵,计算源点到其他顶点的最短距离和路径,适用于计算机科学与信息技术专业人士。

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

【问题描述】Dijkstra算法解决的是带权重的有向图上单源最短路径问题。所有边的权重都为非负值。设置顶点集合S并不断地作贪心选择来扩充这个集合。使用最小堆数据结构构造优先队列。第1个顶点为源。

【输入形式】在屏幕上输入顶点个数和连接顶点间的边的权矩阵。

【输出形式】从源到各个顶点的最短距离及路径。

【样例输入】

5

0 10 0 30 100

0 0 50 0 0

0 0 0 0 10

0 0 20 0 60

0 0 0 0 0

【样例输出】

10: 1->2

50: 1->4->3

30: 1->4

60: 1->4->3->5

【样例说明】

输入:顶点个数为5。连接顶点间边的权矩阵大小为5行5列,位置[i,j]上元素值表示第i个顶点到第j个顶点的距离,0表示两个顶点间没有边连接。

输出:每行表示源1到其余各顶点的最短距离及路径,冒号后有一空格。如果源1到该顶点没有路,则输出:"inf: 1->u",其中u为该顶点编号。

【评分标准】根据输入得到准确的输出。

import numpy as np
import heapq as hq


class VertexNode(object):  # 顶点类
    def __init__(self, index=None, dist=np.inf, previous=None):
        self.index = index
        self.dist = dist
        self.previous = previous

    def __repr__(self):
        return "<Vertex>".format(self.index, self.dist)

    def __lt__(self, other):
        return self.dist < other.dist


'''
输入参数adj_list, 邻接表nx1, 每个元素是一个字典,第i个元素包含的是与第i个顶点相邻的顶点序号及边权值。 
输入参数s_index:源序号 
输出参数s_dict:字典,key值为顶点序号,value值为顶点,刚开始为空,每循环一次,加一个顶点至该字典中
'''


def dijkstra(adj_list, s_index):
    n = len(adj_list)
    min_heap = [VertexNode(index=i) for i in range(n)]
    # 设置源顶点的dist值为0
    min_heap[s_index-1].dist = 0
    hq.heapify(min_heap)
    s_dict = {}
    while len(min_heap):  # 最小堆非空时,循环
        u = min_heap.pop(0)
        s_dict.setdefault(u.index, u)
        for k in adj_list[u.index]:
            # 根据u邻接的顶点序号k,在最小堆中寻找与k相同的顶点index
            for i in range(len(min_heap)):
                if k == min_heap[i].index and min_heap[i].dist > u.dist + adj_list[u.index][k]:
                    min_heap[i].previous = u
                    min_heap[i].dist = u.dist + adj_list[u.index][k]
                    hq.heapify(min_heap)
                if k != min_heap[i].index and min_heap[i].dist == np.inf or min_heap[i].dist == 0:
                    min_heap[i].previous = u
                    min_heap[i].dist = np.inf
    return s_dict


# 输入参数sorted_list:按序号从小到大排列好的元祖列表,存放的是已经具有最短特殊路径的顶点
def show_path(sorted_list):
    for i in range(1, len(sorted_list)):
        pre = sorted_list[i][1].previous.index
        path = str(pre+1) + '->' + str(i+1)
        while pre != 0:
            path = str(sorted_list[pre][1].previous.index+1) + '->' + path
            pre = sorted_list[pre][1].previous.index
        if sorted_list[i][1].dist < np.inf:
            print(str(sorted_list[i][1].dist) + ': ' + path)
        else:
            print(f"{str(sorted_list[i][1].dist)}: 1->{i+1}")


def main():
    n = int(input())  # 顶点个数
    adj_list = [{}]*n  # 初始化邻接列表
    for k in range(n):  # 邻接矩阵
        temp = np.array(input().split(), dtype=np.int8)
        temp_dict = {}
        for i in range(len(temp)):
            if temp[i] != 0:
                temp_dict.setdefault(i, temp[i])
        adj_list[k] = temp_dict
    # 设置编号为1的顶点为源
    s_index = 1
    s_dict = dijkstra(adj_list, s_index)

    # 根据字典中的key值(顶点序号)从小到大排序,成为一个元祖列表
    s_dict_sorted_list = sorted(s_dict.items(), key=lambda x: x[0])
    # for i in range(n):
    #     print(s_dict_sorted_list[i][1].dist)
    # 显示源到各顶点的最短路径及距离
    show_path(s_dict_sorted_list)


if __name__ == '__main__':
    main()


'''
输入样例
5
0 10 0 30 100
0 0 50 0 0
0 0 0 0 10
0 0 20 0 60
0 0 0 0 0
'''

"""
4
0 1 0 5
0 0 0 0
0 0 0 0
0 0 0 0
"""

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值