【问题描述】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
"""