Dijkstra template and practice questions
Dijkstra
Template
It is very similar to BFS, but we use heap
Practice questions
합승 택시 요금
https://school.programmers.co.kr/learn/courses/30/lessons/72413
def solution(n, s, a, b, fares):
distance = [int(10e9) for _ in range(n+1)]
graph = [[] for _ in range(n+1)]
for fare in fares:
start,end,cost = fare
graph[start].append((cost,end))
graph[end].append((cost,start))
heap = []
heappush(heap, [0,s])
# distance[s]=0
while heap:
cost, now = heappop(heap)
if distance[now]<cost:
continue
for ncost, nnext in graph[now]:
if cost+ncost < distance[nnext]:
distance[nnext] = cost+ncost
heappush(heap, (cost+ncost,nnext))
print(distance[a])
print(distance[b])
This prints out the shortest distance from starting point (s) to a and b respectively.
My initial thinking and code is this. First make a distance list via dijkstra that tells the distance of each node from each starting point. We are gonna add this distance when we dijkstra on each node.
from heapq import heappush,heappop
def solution(n, s, a, b, fares):
distance = [int(10e9) for _ in range(n+1)]
graph = [[] for _ in range(n+1)]
minA = int(10e9)
minB = int(10e9)
ans = int(10e9)
for fare in fares:
start,end,cost = fare
graph[start].append((cost,end))
graph[end].append((cost,start))
alter_distance = dijkstra(graph,n,s)
alter_distance_copy = list(alter_distance)
for i in range(1,n+1):
heap = []
heappush(heap, [0,-1,i])
heappush(heap, [0,-2,i])
temp_distance = alter_distance_copy
temp_distance[i]=0
while heap:
cur_cost, charac, curr_node = heappop(heap)
# print(curr_node)
if curr_node == a and charac == -1:
minA = min(minA, cost)
print("minA",minA)
elif curr_node == b and charac == -2:
minB = min(minB,cost)
print("minB",minB)
if temp_distance[curr_node]<cur_cost:
continue
for new_cost, new_end in graph[curr_node]:
cost = cur_cost + new_cost
if temp_distance[new_end]>cost:
temp_distance[new_end] = cost
heappush(heap, [new_cost,charac, new_end])
ans = min(ans, alter_distance[i] +minA +minB)
print(ans)
return ans
# return distance[s]+minA+minB
def dijkstra(graph,n,s):
alter_distance = [int(10e9) for _ in range(n+1)]
toot =[]
heappush(toot,(0,s))
alter_distance[s]=0
while toot:
curr_cost, curr_node = heappop(toot)
if alter_distance[curr_node]<curr_cost:
continue
for new_cost, new_end in graph[curr_node]:
cost = curr_cost + new_cost
if cost<alter_distance[new_end]:
alter_distance[new_end] = cost
heappush(toot, (cost,new_end))
print(alter_distance)
return alter_distance
solution(6, 4 ,6 ,2, [[4, 1, 10], [3, 5, 24], [5, 6, 2], [3, 1, 41], [5, 1, 24], [4, 6, 50], [2, 4, 66], [2, 3, 22], [1, 6, 25]])
but actually we can reuuse the dijkstra without remaking it again to make distance list.
like this: btw VERY CAREFUL to make fresh distance list of infinity values each time dijkstra is performed. If you just pass distance to dijkstra parameter like
dijkstra(n,s,k,graph,distance)
then the same distance list will be used on consecutively by multiple dijkstras without being freshly created.
from heapq import heappush,heappop
def solution(n, s, a, b, fares):
distance = [int(10e9) for _ in range(n+1)]
graph = [[] for _ in range(n+1)]
ans = int(10e6)
for fare in fares:
start,end,cost = fare
graph[start].append((cost,end))
graph[end].append((cost,start))
result = []
for k in range(1,n+1):
if k!=s:
dist_s_to_node = dijkstra(n,s,k,graph)
dist_node_to_a = dijkstra(n,k,a,graph)
dist_node_to_b = dijkstra(n,k,b,graph)
result.append(dist_s_to_node+ dist_node_to_a+ dist_node_to_b)
else:
dist_s_to_a = dijkstra(n,k,a,graph)
dist_s_to_b = dijkstra(n,k,b,graph)
result.append(dist_s_to_a+dist_s_to_b)
return min(result)
def dijkstra(n,s,end,graph):
heap = []
distance = [int(10e9) for _ in range(n+1)]
heappush(heap, [0,s])
distance[s]=0
while heap:
cost, now = heappop(heap)
if distance[now]<cost:
continue
for ncost, nnext in graph[now]:
if cost+ncost < distance[nnext]:
distance[nnext] = cost+ncost
heappush(heap, (cost+ncost,nnext))
# print(distance[end])
return distance[end]
You can use Floyd-Marshall:
# 플로이드-와샬
from math import inf
def solution(n, s, a, b, fares):
# 0부터 시작하는 인덱스
s, a, b = s - 1, a - 1, b - 1
# inf 로 초기화된 거리행렬
# 자기 자신으로 가는 간선 가중치는 0
graph = [[inf] * n for _ in range(n)]
for i in range(n):
graph[i][i] = 0
# 거리행렬에 주어진 비용 넣기
for fare in fares:
u, v, w = fare
graph[u - 1][v - 1] = graph[v - 1][u - 1] = w
# 플로이드-와샬
for k in range(n): # 1. 모든 노드를 중간점(경로)으로 가정하면서
for i in range(n): # 2. 거리행렬을 순회
for j in range(n): # 3. 현재 거리행렬에 저장된 거리가 k를 거쳐가는 거리보다 멀면 갱신
if graph[i][j] > graph[i][k] + graph[k][j]:
graph[i][j] = graph[i][k] + graph[k][j]
# graph[i][j] = min(graph[i][j], graph[i][k] + graph[k][j]) 시간 거의 두 배 걸림..
# 출발점을 기준으로 어떤 지점 k를 거쳐 각각 a와 b로 가는 최소 비용을 탐색
ans = inf
for k in range(n):
ans = min(ans, graph[s][k] + graph[k][a] + graph[k][b])
return ans