弗洛伊德算法
def networkDelayTime(self, times, n, k):
"""
:type times: List[List[int]]
:type n: int
:type k: int
:rtype: int
"""
INTMAX = 0x3f3f3f3f
graph = [[INTMAX]*n for i in range(n)]
for x,y,t in times:
graph[x-1][y-1] = t
for i in range(n):
graph[i][i] = 0
for l in range(n): #经典floyed算法l作为中间点,不断更新经过l的两个节点的最短路径
for i in range(n):
for j in range(n):
if graph[i][j] > graph[i][l] + graph[l][j]:
graph[i][j] = graph[i][l] + graph[l][j]
mint = -1
for i in range(n):
if graph[k-1][i] == INTMAX: #这里表明如果遇到不能到达的节点直接返回-1
return -1
mint = max(mint,graph[k-1][i]) #找由起点开始所有路径中最远的
return mint
BFS
def networkDelayTime(times, n, k):
mp = [{} for i in range(n + 1)]
for u, v, t in times: #邻接表记录可到达的节点以及所需时间
mp[u][v] = t
r = [-1 for i in range(n + 1)] #记录开始节点到各个节点的最短路径长度
r[k] = 0
# 队列中存放 [结点,收到信号时间]
s = deque([[k, 0]])
while s:
cur, t = s.popleft() #当前节点,和当前节点到开始结点的路径长度
for u, v in mp[cur].items(): #u是当前节点对应的邻居节点 v是它们之间的路径长度
art = t + v #更新路径长度
# 仅当结点未收到或收到时间比记录时间更早才更新并入队
if r[u] == -1 or art < r[u]:#更新最短路径 (这里是和迪杰斯特拉算法不同的地方,如果后面的u比前面的u的距离短的话,依然是按顺序执行的,而迪杰斯特拉每次都是找到最短的那个节点开始)
r[u] = art
s.append([u, art]) #邻居节点和长度加入队列
minT = -1
for i in range(1, n + 1):
if r[i] == -1:
return -1
minT = max(minT, r[i]) #返回最长的
return minT
迪杰斯特拉算法(相比上面的广度优先的区别在于没有用到贪心算法的思想。)
def networkDelayTime(self, times, n, k):
"""
:type times: List[List[int]]
:type n: int
:type k: int
:rtype: int
"""
INTMAX = 0x3f3f3f3f
mp = [{} for i in range(n)]
for u,v,t in times: #邻接表,作用是存储相邻边
mp[u-1][v-1] = t
s = [0]*n #访问数组
r = [INTMAX]*n #距离记录
r[k-1] = 0
while True:
cur,d = -1,INTMAX #初始值
for i,t in enumerate(r): #每次都找还没被访问的离起始点最短的那个节点(贪心思想)
if s[i] == 0 and t < d:
cur,d = i,t
if cur == -1: #有连接的都访问过了
break
s[cur] = 1 #把找到的最短的标记为访问过
for u,v in mp[cur].items(): #更新最短的邻居节点距离起始点的距离
r[u] = min(r[u],d+v)
mint = -1
for j in range(n):
if r[j] == INTMAX:
return -1
mint = max(mint,r[j])
return mint
堆优化迪杰斯特拉
def networkDelayTime(self, times, n, k):
"""
:type times: List[List[int]]
:type n: int
:type k: int
:rtype: int
"""
INTMAX = 0x3f3f3f3f
r = [INTMAX]*n
r[k-1] = 0
mp = [{} for i in range(n)]
for x,y,t in times:
mp[x-1][y-1] = t
s = [[0,k-1]]
heapq.heapify(s) #堆化
while s:
curt,node = heapq.heappop(s) #每次弹出来的最小元素,而且是按照列表里第一个元素排序的(在这里就是时间最短的顺序)
if curt > r[node]: #进栈的时候没能控制一定是最小的,所以加个判断,如果curt并不是最小的,那么跳过
continue
for neighbor,weight in mp[node].items(): #查看邻居节点的情况
if r[neighbor] > r[node] + weight: #有更短的入队
r[neighbor] = r[node]+weight #更新r
heapq.heappush(s,[r[neighbor],neighbor])
mint = -1
for j in range(n):
if r[j] == INTMAX:
return -1
mint = max(mint,r[j])
return mint
bellman-ford算法
def networkDelayTime(self, times, n, k):
"""
:type times: List[List[int]]
:type n: int
:type k: int
:rtype: int
"""
INTMAX = 0x3f3f3f3f
r = [INTMAX]*n
r[k-1] = 0
for i in range(n-1): #松弛 图中节点个数减一次
for x,y,t in times: #这里是从x到y及权重 所以到y的路径长度应该等于到x的路径长度加上权重
if r[y-1] > r[x-1] + t:
r[y-1] = r[x-1] + t
for x, y, t in times: #再进行一次松弛操作,如果还有更新说明图中存在负权的环
if r[y - 1] > r[x - 1] + t:
return -1
mint = -1
for j in range(n):
if r[j] == INTMAX:
return -1
mint = max(mint,r[j])
return mint
SPFA,双端队列优化bellman-ford算法,用双端队列记录松弛过的节点,只有松驰过的节点才会对后面路径长度产生影响所以不是所有节点都需要更新
def networkDelayTime(self, times, n, k):
"""
:type times: List[List[int]]
:type n: int
:type k: int
:rtype: int
"""
INTMAX = 0x3f3f3f3f
r = [INTMAX]*n
r[k-1] = 0
mp = [{} for i in range(n)]
for x, y, t in times:
mp[x-1][y-1] = t
queue =deque([k-1]) #记录松驰过的节点
s = set() #加上一个访问数组可以避免重复让相同的节点入队列,加快时间
s.add(k-1)
while queue:
cur = queue.popleft()
s.remove(cur)
for neighbor, t in mp[cur].items():
if r[neighbor] > r[cur] + t:
r[neighbor] = r[cur] + t
if neighbor not in s:
s.add(neighbor)
queue.append(neighbor)
mint = -1
for i in range(n):
if r[i] == INTMAX:
return -1
mint = max(mint,r[i])
return mint