https://leetcode.com/problems/reachable-nodes-in-subdivided-graph/
你有一個n 個點(node)組成的無向圖original graph;接著,有若干個點把這無向圖的邊(edge)切開,標示如下: edges[i] = [ui, vi, cnti] 代表點ui 到點vi 的邊之間插入了cnti 個點;最後,請回傳點0 (node 0) 在距離maxMove 之內可以接觸到幾個點。
這題雖然說edge 之間有新增若干個點,不過我們可以把這些點當作weight,這樣題目看起來就熟悉多了,就像是找最短路徑的那種題目,而今天正是要用Dijkstra's 演算法。
不過Dijkstra's 還不足以解決這題,因為Dijkstra's 只會保留最短路徑,而這題還另外要求在距離maxMove 內可以走到的點,那無向圖的邊就可能有以下幾種可能:
第一種狀況用Dijkstra's 就可以把路徑上的點算進來了;而第二第三種狀況的邊會被Dijkstra's 排除,則要另外把邊長算進來,此外第三種狀況的邊還需要計算走到兩側還剩餘多少maxMove。
不論如何都需要Dijkstra's 演算法,所以先上只有Dijkstra's 演算法的部分,也請參考看看Dijkstra's演算法的影片
class Solution(object):
def reachableNodes(self, edges, M, N):
graph = collections.defaultdict(dict)
for u, v, w in edges:
graph[u][v] = graph[v][u] = w
pq = [(0, 0)] # 等待計算距離的點 [distance, node]
dist = {0: 0} # 紀錄最短距離 {node: distance}
while pq:
d, node = heapq.heappop(pq)
if d > dist[node]: continue
for nei, weight in graph[node].items():
d2 = d + weight + 1 # +1是因為點本身也佔一步距離
if d2 < dist.get(nei, math.inf):
heapq.heappush(pq, (d2, nei))
dist[nei] = d2
# 更新最短路徑
print(dist)
接著是可以通過本題的解法
class Solution(object):
def reachableNodes(self, edges, M, N):
graph = collections.defaultdict(dict)
for u, v, w in edges:
graph[u][v] = graph[v][u] = w
pq = [(0, 0)]
dist = {0: 0}
used = {}
ans = 0
while pq:
d, node = heapq.heappop(pq)
if d > dist[node]: continue
ans += 1
for nei, weight in graph[node].items():
v = min(weight, M - d)
used[node, nei] = v
# min(weight, M - d)會把狀況二、三的邊長記下來
# M - d代表到目前的點還剩多少步可以走,解決第三種狀況
d2 = d + weight + 1
if d2 < dist.get(nei, M+1):
heapq.heappush(pq, (d2, nei))
dist[nei] = d2
for u, v, w in edges:
ans += min(w, used.get((u, v), 0) + used.get((v, u), 0))
return ans
Dijkstra真的很厲害,除了這個演算法外,他還有另一個知名的Banker's algorithm
但是他的名字太難記了,所以我都叫Dijkstra's 演算法為大DD演算法