




import math
import sys





class 						SCREAMING_SNAKE_CASE__		:
     def __init__(	self  :		int	):



       """simple docstring"""
       lowerCAmelCase__								=			0
       lowerCAmelCase__								=			[]
       lowerCAmelCase__								=			{}  # To store the pos of node in array
     def 					A__			(	self  :		Optional[int]	):



       """simple docstring"""
       return self.cur_size == 0
     def 					A__			(	self  :		Union[str, Any]					,	__lowerCamelCase  :		Dict	):



       """simple docstring"""
       lowerCAmelCase__								=			self.left(__lowerCamelCase	)
       lowerCAmelCase__								=			self.right(__lowerCamelCase	)
       if lc < self.cur_size and self.array(__lowerCamelCase	)[0] < self.array(__lowerCamelCase	)[0]:
         lowerCAmelCase__								=			lc
       else:
         lowerCAmelCase__								=			idx
       if rc < self.cur_size and self.array(__lowerCamelCase	)[0] < self.array(__lowerCamelCase	)[0]:
         lowerCAmelCase__								=			rc
       if smallest != idx:
         self.swap(__lowerCamelCase					,	__lowerCamelCase	)
         self.min_heapify(__lowerCamelCase	)
     def 					A__			(	self  :		List[Any]					,	__lowerCamelCase  :		Any	):



       """simple docstring"""
       # Inserts a node into the Priority Queue
       lowerCAmelCase__								=			self.cur_size
       self.cur_size += 1
       self.array.append((sys.maxsize, tup[1])	)
       self.decrease_key((sys.maxsize, tup[1])					,	tup[0]	)
     def 					A__			(	self  :		List[Any]	):



       """simple docstring"""
       # Removes and returns the min element at top of priority queue
       lowerCAmelCase__								=			self.array[0][1]
       lowerCAmelCase__								=			self.array[self.cur_size - 1]
       self.cur_size -= 1
       self.min_heapify(1	)
       del self.pos[min_node]
       return min_node
     def 					A__			(	self  :		Union[str, Any]					,	__lowerCamelCase  :		Optional[int]	):



       """simple docstring"""
       # returns the index of left child
       return 2 * i + 1
     def 					A__			(	self  :		Optional[Any]					,	__lowerCamelCase  :		Tuple	):



       """simple docstring"""
       # returns the index of right child
       return 2 * i + 2
     def 					A__			(	self  :		str					,	__lowerCamelCase  :		Optional[Any]	):



       """simple docstring"""
       # returns the index of parent
       return math.floor(i / 2	)
     def 					A__			(	self  :		int					,	__lowerCamelCase  :		str					,	__lowerCamelCase  :		int	):



       """simple docstring"""
       # swaps array elements at indices i and j
       # update the pos{}
       lowerCAmelCase__								=			j
       lowerCAmelCase__								=			i
       lowerCAmelCase__								=			self.array[i]
       lowerCAmelCase__								=			self.array[j]
       lowerCAmelCase__								=			temp



     def 					A__			(	self  :		str					,	__lowerCamelCase  :		List[str]					,	__lowerCamelCase  :		int	):



       """simple docstring"""
       lowerCAmelCase__								=			self.pos[tup[1]]
       # assuming the new_d is atmost old_d
       lowerCAmelCase__								=			(new_d, tup[1])
       while idx > 0 and self.array[self.par(__lowerCamelCase	)][0] > self.array[idx][0]:
         self.swap(__lowerCamelCase					,	self.par(__lowerCamelCase	)	)
         lowerCAmelCase__								=			self.par(__lowerCamelCase	)





class 						SCREAMING_SNAKE_CASE__		:
     def __init__(	self  :		Optional[Any]					,	__lowerCamelCase  :		str	):



       """simple docstring"""
       lowerCAmelCase__								=			{}  # To store graph: u -> (v,w)
       lowerCAmelCase__								=			num  # Number of nodes in graph
       # To store the distance from source vertex
       lowerCAmelCase__								=			[0] * self.num_nodes
       lowerCAmelCase__								=			[-1] * self.num_nodes  # To store the path
     def 					A__			(	self  :		Optional[int]					,	__lowerCamelCase  :		int					,	__lowerCamelCase  :		Optional[int]					,	__lowerCamelCase  :		str	):



       """simple docstring"""
       #  Edge going from node u to v and v to u with weight w
       # u (w)-> v, v (w) -> u
       # Check if u already in graph
       if u in self.adjList:
         self.adjList[u].append((v, w)	)
       else:
         lowerCAmelCase__								=			[(v, w)]

       # Assuming undirected graph
       if v in self.adjList:
         self.adjList[v].append((u, w)	)
       else:
         lowerCAmelCase__								=			[(u, w)]
     def 					A__			(	self  :		Optional[int]	):



       """simple docstring"""
       # u -> v(w)
       for u in self.adjList:
         print(__lowerCamelCase					,	'''->'''					,	''' -> '''.join(str(F"""{v}({w})"""	) for v, w in self.adjList[u]	)	)
     def 					A__			(	self  :		Any					,	__lowerCamelCase  :		List[Any]	):



       """simple docstring"""
       # Flush old junk values in par[]
       lowerCAmelCase__								=			[-1] * self.num_nodes
       # src is the source node
       lowerCAmelCase__								=			0
       lowerCAmelCase__								=			PriorityQueue()
       q.insert((0, src)	)  # (dist from src, node)
       for u in self.adjList:
         if u != src:
           lowerCAmelCase__								=			sys.maxsize  # Infinity
           lowerCAmelCase__								=			-1

       while not q.is_empty():
         lowerCAmelCase__								=			q.extract_min()  # Returns node with the min dist from source
         # Update the distance of all the neighbours of u and
         # if their prev dist was INFINITY then push them in Q
         for v, w in self.adjList[u]:
           lowerCAmelCase__								=			self.dist[u] + w
           if self.dist[v] > new_dist:
             if self.dist[v] == sys.maxsize:
               q.insert((new_dist, v)	)
             else:
               q.decrease_key((self.dist[v], v)					,	__lowerCamelCase	)
             lowerCAmelCase__								=			new_dist
             lowerCAmelCase__								=			u

        # Show the shortest distances from src
       self.show_distances(__lowerCamelCase	)
     def 					A__			(	self  :		List[str]					,	__lowerCamelCase  :		Any	):



       """simple docstring"""
       print(F"""Distance from node: {src}"""	)
       for u in range(self.num_nodes	):
         print(F"""Node {u} has distance: {self.dist[u]}"""	)



     def 					A__			(	self  :		str					,	__lowerCamelCase  :		Union[str, Any]					,	__lowerCamelCase  :		List[Any]	):



       """simple docstring"""
       # To show the shortest path from src to dest
       # WARNING: Use it *after* calling dijkstra
       lowerCAmelCase__								=			[]
       lowerCAmelCase__								=			0
       lowerCAmelCase__								=			dest
       # Backtracking from dest to src
       while self.par[temp] != -1:
         path.append(__lowerCamelCase	)
         if temp != src:
           for v, w in self.adjList[temp]:
             if v == self.par[temp]:
               cost += w
               break
         lowerCAmelCase__								=			self.par[temp]
       path.append(__lowerCamelCase	)
       path.reverse()

       print(F"""----Path to reach {dest} from {src}----"""	)
       for u in path:
         print(F"""{u}"""					,	end=''' '''	)
         if u != dest:
           print('''-> '''					,	end=''''''	)

       print('''\nTotal cost of path: '''					,	__lowerCamelCase	)


if __name__ == "__main__":
      __magic_name__     :     Optional[int]  							=					Graph(9)
      graph.add_edge(0, 1, 4)
      graph.add_edge(0, 7, 8)
      graph.add_edge(1, 2, 8)
      graph.add_edge(1, 7, 11)
      graph.add_edge(2, 3, 7)
      graph.add_edge(2, 8, 2)
      graph.add_edge(2, 5, 4)
      graph.add_edge(3, 4, 9)
      graph.add_edge(3, 5, 14)
      graph.add_edge(4, 5, 10)
      graph.add_edge(5, 6, 2)
      graph.add_edge(6, 7, 1)
      graph.add_edge(6, 8, 6)
      graph.add_edge(7, 8, 7)
      graph.show_graph()
      graph.dijkstra(0)
      graph.show_path(0, 4)

# OUTPUT
# 0 -> 1(4) -> 7(8)
# 1 -> 0(4) -> 2(8) -> 7(11)
# 7 -> 0(8) -> 1(11) -> 6(1) -> 8(7)
# 2 -> 1(8) -> 3(7) -> 8(2) -> 5(4)
# 3 -> 2(7) -> 4(9) -> 5(14)
# 8 -> 2(2) -> 6(6) -> 7(7)
# 5 -> 2(4) -> 3(14) -> 4(10) -> 6(2)
# 4 -> 3(9) -> 5(10)
# 6 -> 5(2) -> 7(1) -> 8(6)
# Distance from node: 0
# Node 0 has distance: 0
# Node 1 has distance: 4
# Node 2 has distance: 12
# Node 3 has distance: 19
# Node 4 has distance: 21
# Node 5 has distance: 11
# Node 6 has distance: 9
# Node 7 has distance: 8
# Node 8 has distance: 14
# ----Path to reach 4 from 0----
# 0 -> 7 -> 6 -> 5 -> 4
# Total cost of path:  21







from __future__ import annotations

from collections.abc import Iterator
from typing import Any





class 						SCREAMING_SNAKE_CASE__		:
     def __init__(	self  :		int					,	__lowerCamelCase  :		Any	):



       """simple docstring"""
       lowerCAmelCase__								=			data
       lowerCAmelCase__								=			None



     def __str__(	self  :		int	):



       """simple docstring"""
       return F"""{self.data}"""





class 						SCREAMING_SNAKE_CASE__		:
     def __init__(	self  :		Union[str, Any]	):



       """simple docstring"""
       lowerCAmelCase__								=			None
       lowerCAmelCase__								=			None
     def __iter__(	self  :		List[Any]	):



       """simple docstring"""
       lowerCAmelCase__								=			self.front
       while node:
         yield node.data
         lowerCAmelCase__								=			node.next
     def __len__(	self  :		int	):



       """simple docstring"""
       return len(tuple(iter(self	)	)	)
     def __str__(	self  :		Optional[int]	):



       """simple docstring"""
       return " <- ".join(str(__lowerCamelCase	) for item in self	)
     def 					A__			(	self  :		Tuple	):



       """simple docstring"""
       return len(self	) == 0
     def 					A__			(	self  :		str					,	__lowerCamelCase  :		Any	):



       """simple docstring"""
       lowerCAmelCase__								=			Node(__lowerCamelCase	)
       if self.is_empty():
         lowerCAmelCase__								=			lowerCAmelCase__								=			node
       else:
         assert isinstance(self.rear					,	__lowerCamelCase	)
         lowerCAmelCase__								=			node
         lowerCAmelCase__								=			node
     def 					A__			(	self  :		Optional[Any]	):



       """simple docstring"""
       if self.is_empty():
         raise IndexError('''dequeue from empty queue'''	)
       assert isinstance(self.front					,	__lowerCamelCase	)
       lowerCAmelCase__								=			self.front
       lowerCAmelCase__								=			self.front.next
       if self.front is None:
         lowerCAmelCase__								=			None
       return node.data



     def 					A__			(	self  :		Tuple	):



       """simple docstring"""
       lowerCAmelCase__								=			lowerCAmelCase__								=			None


if __name__ == "__main__":
      from doctest import testmod

      testmod()

