蓝桥杯算法题 ALGO-5 最短路
原题链接:link.
给定一个n个顶点,m条边的有向图(其中某些边权可能为负,但保证没有负环)。请你计算从1号点到其他点的最短路(顶点从1到n编号)。
第一行两个整数n, m。
接下来的m行,每行有三个整数u, v, l,表示u到v有一条长度为l的边。
共n-1行,第i行表示1号点到i+1号点的最短路。
3 3
1 2 -1
2 3 -1
3 1 2
-1
-2
对于10%的数据,n = 2,m = 2。
对于30%的数据,n <= 5,m <= 10。
对于100%的数据,1 <= n <= 20000,1 <= m <= 200000,-10000 <= l <= 10000,保证从任意顶点都能到达其他所有顶点。
树形动态规划算法题,最短路径问题。
由于有负权值,不能够使用Dijkstra算法。
Floyd算法、BF(Bellman-Ford)算法由于时间复杂度较大,存在超时可能。
这里考虑SPFA算法,通过松弛边的方法,维护可能的结点FIFO队列line与各点到结点1的距离列表dis。
(注:SPFA 最坏情况下复杂度和朴素 Bellman-Ford 相同)
这里存储边的数据结构的选择会影响后面SPFA算法的运行时间。
经过尝试,字典的列表形式优于二维数组的形式,能够提高访问效率。
# 字典的列表:
[{
},{
"j":weight},{
},{
},...{
}]
# 列表中第i个字典中键j及其值weight代表结点i与结点j之间的权重为weight
# 二维数组
[ [0,0,0, ... , 0] ,
[0,0,0, ... , 0] ,
... ,
[0,0,0, ... , 0] ]
# SPFA
# 蓝桥杯 最短路
# Author:韩仙男 2021-01-28
n,m = map(int,input().split())
dis = [float("inf") for _ in range(n)]
dis[0] = 0
edges = [ dict() for _ in range(n)]
for _ in range(m):
f,t,weight = map(int,input().split())
edges[f-1][t] = weight
line = [1]
while line != []:
current_point = line[0]
for t_point,weight in edges[current_point-1].items():
if dis[t_point-1] > dis[current_point-1] + weight:
dis[t_point-1] = dis[current_point-1] + weight
if t_point not in line:
line.append(t_point)
line.remove(current_point)
for _ in range(1,n):
print(dis[_])