[LeetCode] Network Delay Time 网络延迟时间——最短路算法 Bellman-Ford(DP) 和 dijkstra(本质上就是BFS的迭代变种) 动态规划,要会模板!
https://leetcode.com/problems/network-delay-time/
There are N
network nodes, labelled 1
to N
.
Given times
, a list of travel times as directed edges times[i] = (u, v, w)
, where u
is the source node, v
is the target node, and w
is the time it takes for a signal to travel from source to target.
Now, we send a signal from a certain node K
. How long will it take for all nodes to receive the signal? If it is impossible, return -1
.
Note:
N
will be in the range[1, 100]
.K
will be in the range[1, N]
.- The length of
times
will be in the range[1, 6000]
. - All edges
times[i] = (u, v, w)
will have1 <= u, v <= N
and1 <= w <= 100
.
这道题给了我们一些有向边,又给了一个结点K,问至少需要多少时间才能从K到达任何一个结点。这实际上是一个有向图求最短路径的问题,我们求出K点到每一个点到最短路径,然后取其中最大的一个就是需要的时间了。
可以想成从结点K开始有水流向周围扩散,当水流到达最远的一个结点时,那么其他所有的结点一定已经流过水了。最短路径的常用解法有迪杰克斯特拉算法Dijkstra Algorithm, 弗洛伊德算法Floyd-Warshall Algorithm, 和贝尔曼福特算法Bellman-Ford Algorithm,其中,Floyd算法是多源最短路径,即求任意点到任意点到最短路径,而Dijkstra算法和Bellman-Ford算法是单源最短路径,即单个点到任意点到最短路径。这里因为起点只有一个K,所以使用单源最短路径就行了。这三种算法还有一点不同,就是Dijkstra算法处理有向权重图时,权重必须为正,而另外两种可以处理负权重有向图,但是不能出现负环,所谓负环,就是权重均为负的环。为啥呢,这里要先引入松弛操作Relaxtion,这是这三个算法的核心思想,当有对边 (u, v) 是结点u到结点v,如果 dist(v) > dist(u) + w(u, v),那么 dist(v) 就可以被更新,这是所有这些的算法的核心操作。Dijkstra算法是以起点为中心,向外层层扩展,直到扩展到终点为止。根据这特性,用BFS来实现时再好不过了。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | class Solution( object ): def networkDelayTime( self , times, N, K): """ :type times: List[List[int]] :type N: int :type K: int :rtype: int """ inf = float ( 'inf' ) dp = [inf] * (N + 1 ) dp[K] = 0 for i in range ( 1 , N): # N+1 is not neccessary for u,v,w in times: #if v == i: dp[v] = min (dp[v], dp[u] + w) max_d = max (dp[ 1 :]) return - 1 if max_d = = inf else max_d |
注意:(1) 我以为是要加一个if判断,实际上是错的。迭代是针对图里所有边,第一次迭代找到的是source点走一次直接连接的最短路。第二次是走二次的最短路迭代。一直到第n-1次走的最短路。
(2)为啥是1,N而不是N+1。
为什么要循环n-1次?图有n个点,又不能有回路,所以最短路径最多n-1边。又因为每次循环,至少relax一边所以最多n-1次就行了!
dijkstra解法:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 | class Solution( object ): def networkDelayTime( self , times, N, K): """ :type times: List[List[int]] :type N: int :type K: int :rtype: int """ return self .dijkstra(times, N, K) def dijkstra(sefl, times, N, k): G = collections.defaultdict( dict ) for n1, n2, w in times: G[n1][n2] = w inf = float ( 'inf' ) dist = {node:inf for node in range ( 1 , N + 1 )} dist[k] = 0 nodes = set ( range ( 1 , N + 1 )) while nodes: node = min (nodes, key = dist.get) # update dist for n in G[node]: dist[n] = min (dist[n], dist[node] + G[node][n]) # node visited nodes.remove(node) max_dist = - 1 for node in dist: if node ! = k: max_dist = max (max_dist, dist[node]) return max_dist if max_dist ! = inf else - 1 |
或者将dist数据结构修改为list
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 | class Solution( object ): def networkDelayTime( self , times, N, K): """ :type times: List[List[int]] :type N: int :type K: int :rtype: int """ return self .dijkstra(times, N, K) def dijkstra(sefl, times, N, k): G = collections.defaultdict( dict ) for n1, n2, w in times: G[n1][n2] = w inf = float ( 'inf' ) dist = [inf] * (N + 1 ) dist[k] = 0 nodes = set ( range ( 1 , N + 1 )) while nodes: node = min (nodes, key = dist.__getitem__) # update dist for n in G[node]: dist[n] = min (dist[n], dist[node] + G[node][n]) # node visited nodes.remove(node) max_dist = max (dist[ 1 :]) return max_dist if max_dist ! = inf else - 1 |
==》dj的见bfs模板,上面自己写的不优雅!
787. K 站中转内最便宜的航班
有 n
个城市通过一些航班连接。给你一个数组 flights
,其中 flights[i] = [fromi, toi, pricei]
,表示该航班都从城市 fromi
开始,以价格 pricei
抵达 toi
。
现在给定所有的城市和航班,以及出发城市 src
和目的地 dst
,你的任务是找到出一条最多经过 k
站中转的路线,使得从 src
到 dst
的 价格最便宜 ,并返回该价格。 如果不存在这样的路线,则输出 -1
。
示例 1:
输入: n = 3, edges = [[0,1,100],[1,2,100],[0,2,500]] src = 0, dst = 2, k = 1 输出: 200 解释: 城市航班图如下

从城市 0 到城市 2 在 1 站中转以内的最便宜价格是 200,如图中红色所示。
示例 2:
输入: n = 3, edges = [[0,1,100],[1,2,100],[0,2,500]] src = 0, dst = 2, k = 0 输出: 500 解释: 城市航班图如下

从城市 0 到城市 2 在 0 站中转以内的最便宜价格是 500,如图中蓝色所示。
解题思路见:https://leetcode.cn/problems/cheapest-flights-within-k-stops/solution/k-zhan-zhong-zhuan-nei-zui-bian-yi-de-ha-abzi/
本质上 就是Bellman-Ford(DP) ,
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | from collections import defaultdict from heapq import heappush, heappop class Solution: def findCheapestPrice( self , n: int , flights: List [ List [ int ]], src: int , dst: int , k: int ) - > int : pre = [ float ( "inf" )] * n pre[src] = 0 for _ in range (k + 1 ): cur = pre[:] for i, j, p in flights: if pre[i] + p < cur[j]: cur[j] = pre[i] + p pre = cur[:] return pre[dst] if pre[dst] < float ( "inf" ) else - 1 |
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 记一次.NET内存居高不下排查解决与启示
· 探究高空视频全景AR技术的实现原理
· 理解Rust引用及其生命周期标识(上)
· 浏览器原生「磁吸」效果!Anchor Positioning 锚点定位神器解析
· 没有源码,如何修改代码逻辑?
· 全程不用写代码,我用AI程序员写了一个飞机大战
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· 记一次.NET内存居高不下排查解决与启示
· 白话解读 Dapr 1.15:你的「微服务管家」又秀新绝活了
· DeepSeek 开源周回顾「GitHub 热点速览」
2016-12-09 英语中逗号作用
2016-12-09 splunk LB和scale(根本在于分布式扩展index,search)
2016-12-09 Splunk Enterprise architecture——转发器本质上是日志收集client附加负载均衡,indexer是分布式索引,外加一个集中式管理协调的中心节点
2016-12-09 c中gets函数使用可能导致缓冲区溢出
2016-12-09 日志易——中国版的splunk