0733. Network Delay Time#
Related Problem:
Problem#
You are given a network of n
nodes, labeled from 1
to n
. You are also given times, a list of travel times as directed edges times[i] = (ui, vi, wi)
, where ui
is the source node, vi
is the target node, and wi
is the time it takes for a signal to travel from source to target.
We will send a signal from a given node k
. Return the minimum time it takes for all the n
nodes to receive the signal. If it is impossible for all the n
nodes to receive the signal, return -1
.
Examples#
Example 1:
Input: times = [[2,1,1],[2,3,1],[3,4,1]], n = 4, k = 2
Output: 2
Example 2:
Input: times = [[1,2,1]], n = 2, k = 1
Output: 1
Example 3:
Input: times = [[1,2,1]], n = 2, k = 2
Output: -1
Constraints:#
1 <= k <= n <= 100
1 <= times.length <= 6000
times[i].length == 3
1 <= ui, vi <= n
ui != vi
0 <= wi <= 100
All the pairs (ui, vi) are unique. (i.e., no multiple edges.)
Analysis#
Shortest Path Problem using Dijkstra’s algorithm
Solution#
# why the following code is wrong? seems cannot deal wtih the case where there are multiple paths between two nodes
# Dijkstra's algorithm do not need to use visited set, because the distance is always the shortest distance from the source node to the current node
def networkDelayTime(times, n, k):
def buildGraph(times):
graph = {}
weights = {}
for i in range(1, n+1):
graph[i] = []
for u, v, w in times:
graph[u].append(v)
weights[(u,v)] = w
return graph, weights
# initialize a visited set
visited = set()
# initialize a distance dict
distance = {node: float('inf') for node in range(1, n+1)}
distance[k] = 0
# build graph
graph, weights = buildGraph(times)
# initialize a queue with distance to source node as key and node as value
queue = [(distance[k], k)]
# loop until queue is empty
while queue:
# pop the node with the shortest distance to source node
dist, node = queue.pop()
# if the node is already visited, skip
visited.add(node)
# update the distance to the neighbors of the node
for neighbor in graph[node]:
# enqueue the neighbor if it is not visited
if neighbor not in visited:
queue.append((dist + weights[(node, neighbor)], neighbor))
# update the distance to the neighbor if the distance to the neighbor is larger than the distance to the node plus the weight of the edge
distance[neighbor] = min(distance[neighbor], dist + weights[(node, neighbor)])
# return the maximum distance
maxDist = max(distance.values())
return maxDist if maxDist != float('inf') else -1
# test
# 2
times = [[2,1,1],[2,3,1],[3,4,1]]
n = 4
k = 2
print(networkDelayTime(times, n, k))
# 1
times = [[1,2,1]]
n = 2
k = 1
print(networkDelayTime(times, n, k))
# -1
times = [[1,2,1]]
n = 2
k = 2
print(networkDelayTime(times, n, k))
# 3
times = [[1,2,1],[2,3,2],[1,3,4]]
n = 3
k = 1
print(networkDelayTime(times, n, k))
# 59
times = [[4,2,76],[1,3,79],[3,1,81],[4,3,30],[2,1,47],[1,5,61],[1,4,99],[3,4,68],[3,5,46],[4,1,6],[5,4,7],[5,3,44],[4,5,19],[2,3,13],[3,2,18],[1,2,0],[5,1,25],[2,5,58],[2,4,77],[5,2,74]]
n = 5
k = 3
print(networkDelayTime(times, n, k))
2
1
-1
3
65
The above code is not correct when the graph is bidirectional, such as a communication network, because visited
set avoids multiple visiting of the same node, which is needed in a bidirectional graph though.
What’s more, typical Dijkstra’s algorithm do not use visited
as it is not necessary.
def networkDelayTime(times, n, k):
def buildGraph(times):
graph = {}
weights = {}
for i in range(1, n+1):
graph[i] = []
for u, v, w in times:
graph[u].append(v)
weights[(u,v)] = w
return graph, weights
# initialize a distance dict
distance = {node: float('inf') for node in range(1, n+1)}
distance[k] = 0
# build graph
graph, weights = buildGraph(times)
# initialize a queue with distance to source node as key and node as value
queue = [(distance[k], k)]
# loop until queue is empty
while queue:
# pop the node with the shortest distance to source node
dist, node = queue.pop()
# update the distance to the neighbors of the node
for neighbor in graph[node]:
# distance to neighbor
distToNeighbor = dist + weights[(node, neighbor)]
# if the recorded distance to neighbor is larger than the distance to the node plus the weight of the edge
if distance[neighbor] > distToNeighbor:
# update distance table and enqueue the neighbor
distance[neighbor] = distToNeighbor
queue.append((distance[neighbor], neighbor))
# return the maximum distance
maxDist = max(distance.values())
return maxDist if maxDist != float('inf') else -1
# test
# 2
times = [[2,1,1],[2,3,1],[3,4,1]]
n = 4
k = 2
print(networkDelayTime(times, n, k))
# 1
times = [[1,2,1]]
n = 2
k = 1
print(networkDelayTime(times, n, k))
# -1
times = [[1,2,1]]
n = 2
k = 2
print(networkDelayTime(times, n, k))
# 3
times = [[1,2,1],[2,3,2],[1,3,4]]
n = 3
k = 1
print(networkDelayTime(times, n, k))
# 59
times = [[4,2,76],[1,3,79],[3,1,81],[4,3,30],[2,1,47],[1,5,61],[1,4,99],[3,4,68],[3,5,46],[4,1,6],[5,4,7],[5,3,44],[4,5,19],[2,3,13],[3,2,18],[1,2,0],[5,1,25],[2,5,58],[2,4,77],[5,2,74]]
n = 5
k = 3
print(networkDelayTime(times, n, k))
2
1
-1
3
59