Python program for Shortest path of a weighted graph where weight is 1 or 2

In this article, we are going to write code to find the shortest path of a weighted graph where weight is 1 or 2. since the weight is either 1 or 2. Whenever there is a weight of two, we will add an extra edge between them and make each weight to 1. Here we will first go through how to create a graph then we will use bfs and create the array of previously visited nodes. From the previously visited array, we will construct the path.

Graph Representation

So First we need to represent the graph in a way computationally feasible. I’m going to represent in an adjacency list. where for every node in the graph we will maintain a list of neighboring nodes. Let’s code

from collections import defaultdict
class Graph:

  def __init__(self,numVertices):
    self.numVertices = numVertices
    #For every node we had a list mapped to it with default dict.
    self.graph = defaultdict(list)

Here the graph variable contains a defaultdict with nodes mapping to list of neighboring edges. but we have to write a function to create edges and maintain lists for each. The below function will create that mapping. All the functions are written inside the Graph class.

def addEdge(self,edge_start,edge_end,edge_weight):

    if edge_weight==1:
      self.graph[edge_start].append(edge_end)
      #if edge weight is one the we directly add to list of neighbors of that particular node

    else:
      #if the edge weight is not one we will add one more edge and make both the edge weights to 1
      self.graph[edge_start].append(self.numVertices)
      # we are adding it as the last vertex and update it's neighbours
      self.graph[self.numVertices].append(edge_end)
      #we will increase the numVertices since one more vertex added
      self.numVertices+=1
Suppose there is an edge between node 4 and node 5 with weight 2. 
4--(2)-->5
we will make it as 4 --(1)--> 6 --(1)--> 5
so that all edges have weight 1.

The reason for changing the edge weights from 2 to 1  is we can make use of BFS to find the shortest path in a graph. If you don’t know the breadth-first search, Please go through this article first.

Shortest Path

During the breadth-first search we main an extra array to save the parent of each node, the index is the node, and value at index is the parent of the index. With the help of this array, we can construct the path. Let’s see the Python code:

def shortestPath(self,src,dest):
    visited = [False]*self.numVertices

    queue  = [src]
    visited[src]=True
    #prev is the extra array we maintain.
    prev = [None for i in range(self.numVertices)]

    while len(queue)!=0:
      s = queue.pop(0)

      for i in self.graph[s]:
        if visited[i]==False:
          queue.append(i)
          visited[i]=True
          # When we visited a node at that index we will have a value s 
          #since from s we are coming to this i
          prev[i] = s
          if i==dest:
            print(prev)
            #When we find the dest we will break 
            #and call construct path to get the path.
            print(self.ConstructPath(src,dest,prev))
            print("Found!!!")
            break

Now we have to construct the path from the extra array.

Construct Path

we will start with the index of destination and then we will go to the value of prev[index] as an index and continue till we find the source. while doing we will add to the path and we will reverse that to get the output. Let’s code:

def ConstructPath(self,src,dest,prev):
  path = [dest]
  index = prev[dest]
  path.append(index)
  count = len(prev)
  while(count>0):
    index = prev[index]
    path.append(index)
    count-=1
    if prev[index]==src:
      path.append(prev[index])
      path.reverse()
      return "-->".join(map(str,path))
  return "Not Found!"

So this is our way to solve this problem. Below is the overall code.

from collections import defaultdict
class Graph:

  def __init__(self,numVertices):
    self.numVertices = numVertices
    self.graph = defaultdict(list)

  def addEdge(self,edge_start,edge_end,edge_weight):
    if edge_weight==1:
      self.graph[edge_start].append(edge_end)
    else:
      self.graph[edge_start].append(self.numVertices)
      self.graph[self.numVertices].append(edge_end)
      self.numVertices+=1
  def printGraph(self):
    for i in range(self.numVertices):
      print(f"{i}--->{self.graph[i]} ")
  def shortestPath(self,src,dest):
    visited = [False]*self.numVertices

    queue  = [src]
    visited[src]=True
    prev = [None for i in range(self.numVertices)]

    while len(queue)!=0:
      s = queue.pop(0)

      for i in self.graph[s]:
        if visited[i]==False:
          queue.append(i)
          visited[i]=True
          prev[i] = s
          if i==dest:
            print(prev)
            print(self.ConstructPath(src,dest,prev))
            print("Found!!!")
            break
    print("Not Found!!")
  def ConstructPath(self,src,dest,prev):
    path = [dest]
    index = prev[dest]
    path.append(index)
    count = len(prev)
    while(count>0):
      index = prev[index]
      path.append(index)
      count-=1
      if prev[index]==src:
        path.append(prev[index])
        path.reverse()
        return "-->".join(map(str,path))
    return "Not Found!"

if __name__=='__main__':
  g = Graph(7)
  g.addEdge(0, 1, 1)
  g.addEdge(1,2,2)
  g.addEdge(1,3,1)
  g.addEdge(2,3,1)
  g.addEdge(3,6,1)
  g.addEdge(0,2,2)
  g.addEdge(0,5,1)
  g.addEdge(5,4,2)
  g.addEdge(4,3,2)
  g.addEdge(4,6,1) 
  g.printGraph()
  g.shortestPath(0,6)

Output:
0–>1–>3–>6
The input is the below graph:

weighted Graph

Feel free to share your thoughts and doubts down in the comment section.

Leave a Reply