特别鸣谢:来自夸夸群的 醉笑陪公看落花@知乎,王不懂不懂@知乎,
感谢醉笑陪公看落花@知乎 倾囊相授,感谢小伙伴们督促学习,一起进步
相关文章
问题描述
有 n 个网络节点,标记为 1 到 n。
给你一个列表 times,表示信号经过 有向 边的传递时间。 times[i] = (ui, vi, wi),其中 ui 是源节点,vi 是目标节点, wi 是一个信号从源节点传递到目标节点的时间。
现在,从某个节点 K 发出一个信号。需要多久才能使所有节点都收到信号?如果不能使所有节点收到信号,返回 -1 。
输入:times = [[2,1,1],[2,3,1],[3,4,1]], n = 4, k = 2
输出:2
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/network-delay-time
方法1:迪杰斯特拉方法实现示意图 (dijkstra)
u为起点:
- 找: 每次找没有处理过的结点v且距离u最近的点
- 更: 用三角不等式更新v的邻结点与u的距离
需要维护一个距离表和一个路径表,本题不需要返回路径,可以不用维护路径表
代码实现
class Solution:
def networkDelayTime(self, times: List[List[int]], n: int, k: int) -> int:
dic = generateGraph(times)
if k not in dic:return -1
dist = SP(dic, k, n)
ans = -1 if max(dist[1:]) == float('inf') else max(dist[1:])
return ans
'''
最短路径
迪杰斯特拉方法实现 (dijkstra)
'''
def SP(dic,u,n):
visited = [False for i in range(n+1)]
dist = [float('inf') for i in range(n+1)]
dist[u] = 0
for v1 in dic[u]:
dist[v1]=dic[u][v1]
while True:
v = -1
for i in range(n+1): # 找没有处理过的结点v且距离u最近的点
if visited[i]: continue
if v<0 or dist[v]>dist[i]:v=i
if v<0:return dist
visited[v] = True
if v not in dic:continue
for v1 in dic[v]: # 找v的邻结点b 根据三角不等式计算结果,取 u-v-b 和u-b二者最小值作为u到b的距离,
if visited[v1]:continue
if dist[v]+dic[v][v1]<dist[v1]:dist[v1] = dist[v]+dic[v][v1]
def generateGraph(times):
dic = {}
for u,v,i in times:
if u not in dic:dic[u] ={}
dic[u][v]=i
return dic
记录路径的迪杰斯特拉算法实现
主要是在找和更新的时候,都存一下路径
路径表中存该节点的前一个节点,反向遍历就能指向起点
def SP(dic,u,n):
visited = [False for i in range(n+1)]
dist = [float('inf') for i in range(n+1)]
path = [0]*(n+1) # 记录路径
dist[u] = 0
for v1 in dic[u]:
dist[v1]=dic[u][v1]
path[v1] = u # 记录路径
while True:
v = -1
for i in range(n+1): # 找没有处理过的结点且距离u最近的点
if visited[i]: continue
if v<0 or dist[v]>dist[i]:v=i
if v<0:return dist,path
visited[v] = True
if v not in dic:continue
for v1 in dic[v]:
if visited[v1]:continue
if dist[v]+dic[v][v1]<dist[v1]:
dist[v1] = dist[v]+dic[v][v1]
path[v1] = v # 记录路径
def generateGraph(times):
dic = {}
for u,v,i in times:
if u not in dic:dic[u] ={}
dic[u][v]=i
for u,v,i in times:
if v not in dic:dic[v] ={}
dic[v][u]=i
return dic
def main(times,n,k):
dic = generateGraph(times)
if k not in dic:return -1
dist = SP(dic, k, n)
ans = -1 if max(dist[1:]) == float('inf') else max(dist[1:])
return ans
方法2: 弗洛伊德算法实现(Floyd)
两个节点之间插点, 给出任意一个节点,在任意两个节点之间插点,如果查入的这个点让距离变短就更新
'''
多源最短路径
'''
def generateG(times,n):
D = [[float('inf')]*n for i in range(n)]
for i,j,w in times:D[i][j]=w
return D
def Floyd(D):
'''
两个节点之间插点
给出任意一个节点,在任意两个节点之间插点,如果距离变短就更新
:param D: 初始时是图的邻接矩阵
D 更新 之后是最小距离矩阵,其中,aij 是i到j最小距离
P 是路径矩阵
'''
P = deepcopy(D)
for i in range(len(D)):
for j in range(len(D)):
if D[i][j]!=float('inf'):P[i][j]=j
for k in range(1,len(D)):
for i in range(1,len(D)):
for j in range(1,len(D)):
if i==j:continue
if D[i][k]==('inf'):
continue
if D[k][j]==('inf'):
continue
if D[i][k]+D[k][j]<D[i][j] :
D[i][j] = D[i][k]+D[k][j]
P[i][j] = k
return P,D
def main(times,n,k):
D = generateG(times, n + 1)
P, D = Floyd(D)
D[k].pop(k) # 删除自己和自己的连接距离
D[k].pop(0) # 图的节点从1开始算的,0号位置要去掉
ans = -1 if max(D[k]) == float('inf') else max(D[k])
return ans
图的几种表示方法
- 三元组: 起点,终点,边权重
times = [[1, 2, 10], [1, 3, 2], [3, 4, 1],[2,4,2],[4,5,3]]
n = 5 # 结点总数
- 狼牙数组
列表里的第1个列表 [1,2] 表示: 起点0 终点 1和2
graph = [[1,2],[2,3],[5],[0],[5],[],[]]
- 字典表示图
有向图
u表示起点,v表示终点,键值表示权重
def generateGraph(times):
dic = {}
for u,v,i in times:
if u not in dic:dic[u] ={}
dic[u][v]=i
return dic
无向图
在有向图基础上,反向再存一遍
def generateGraph(times):
dic = {}
for u,v,i in times:
if u not in dic:dic[u] ={}
dic[u][v]=i
for u,v,i in times:
if v not in dic:dic[v] ={}
dic[v][u]=i
return dic
- 矩阵存图(邻接矩阵)
def generateG(times,n):
D = [[float('inf')]*n for i in range(n)]
for i,j,w in times:D[i][j]=w
return D
邻接矩阵A
A^n
中的元素aij
表示 i
到j
的路径长度为n
的时候,有 aij
种走法