Open In App

D’Esopo-Pape Algorithm : Single Source Shortest Path

Improve
Improve
Improve
Like Article
Like
Save Article
Save
Share
Report issue
Report

Given a graph and a source vertex src in a weighted undirected graph, find the shortest paths from src to all vertices in the given graph. The graph may contain negative weight edges.

For this problem, we have already discussed Dijkstra’s algorithm and Bellman-Ford Algorithm. But D’Esopo-Pape Algorithm performs quite well in most of the cases. However there are some cases in which it takes exponential time.
 

Algorithm:
Input: Adjacency List of the graph and source vertex src. 
Output: Shortest distance to all vertices from src.
This Algorithm uses a Bi-directional queue that stores the vertices to be operated. 

Following are the detailed steps of the algorithm. 

  1. Initialize distance of the vertices from source to infinite in an array.
  2. Maintain a Queue which will store the vertices to be operated and also maintain a Boolean array for vertices which will be used to decide that the vertex is already present in the queue or not.
  3. Append source vertex in the queue.
  4. Start popping vertices from the queue until queue is empty, and perform following steps for each popped vertex(let U be the popped vertex) : 
    • Set the vertex U as not present in the queue.
    • For each adjacent vertex V of U, check if its current minimum Distance[V] is greater than the distance through U
      i.e. Distance[U] + weight of edge connecting U and V.
    • If yes, update Distance[V] = Distance[U] + weight of edge connecting U and V. 
      Check If V is not present in the queue with the help of Boolean Array: 
      1. If V is entering the queue for the first time, append V at the back of the queue and set vertex V as present in the queue with the help of Boolean Array.
      2. Else append in the front of the queue and set V vertex as present in the queue.
  5. Return list Distance which will have shortest distance of every vertex from the source vertex.

For Example: 
Initially, the Distance from source to itself will be 0 and for other vertices it will be infinite.  

Now for each Adjacent vertex of source that is 0 in this case are [1, 4] update the distance and mark the vertices as present in the with weight of 4 and 8 respectively.  

Now Dequeue the vertex 4 from the queue and following are the adjacent vertices are connected to the vertex 4 – 

  • Vertex 1 – As Vertex 1 have already visited and the weight to reach the vertex 1 is 4, whereas when move to vertex 1 via the edge 4 — 1 from source the total weight will be 11 which is greater than weight stored in the distance array.
  • Vertex 3 – As Vertex 3 is not visited and also not present in the queue, So the distance is updated to 9 for vertex 3 and also enqueued into the queue at the front.

Similarly Dequeue the vertex 3 from the Queue and update the values for adjacent vertex. Adjacent vertices of the vertex 3 is vertex 4 and vertex 2. 

  • Vertex 4 – As vertex 4 is already visited and the weight is already minimum So Distance is not updated.
  • Vertex 2 – As Vertex 2 is not visited and also not present in the queue, So the distance is updated to 11 for vertex 3 and also enqueued into the queue at the front.

Below is the implementation of the above approach.  

C++




// C++ implementation for
// D'Esopo-Pape algorithm
#include <bits/stdc++.h>
using namespace std;
#define inf INT_MAX
 
vector<int> desopo(vector<vector<int>> &graph)
{
   
  // Number of vertices in graph
  int v = graph.size();
 
  // Adjacency list of graph
  map<int, vector<pair<int, int>>> adj;
  for(int i = 0; i < v; i++) {
    for(int j = i + 1; j < v; j++)
    {
      if (graph[i][j] != 0)
      {
        adj[i].push_back({graph[i][j], j});
        adj[j].push_back({graph[i][j], i});
      }
    }
  }
 
  // Queue to store unoperated vertices
  deque<int> q;
 
  // Distance from source vertex
  // distance =[float('inf')]*v
  vector<int> distance(v, inf);
 
  // Status of vertex
  vector<bool> is_in_queue(v, false);
 
  // let 0 be the source vertex
  int source = 0;
  distance = 0;
  q.push_back(source);
  is_in_queue = true;
 
  while (!q.empty())
  {
     
    // Pop from front of the queue
    int u = q.front();
    q.pop_front();
    is_in_queue[u] = false;
 
    // Scan adjacent vertices of u
    for(auto e : adj[u])
    {
       
      // e <- [weight, vertex]
      if (distance[e.second] >
          distance[u] + e.first)
      {
        distance[e.second] = distance[u] + e.first;
        if (!is_in_queue[e.second])
        {
           
          // if e.second is entering
          // first time in the queue
          if (distance[e.second] == inf)
             
            // Append at back of queue
            q.push_back(e.second);
          else
             
            // Append at front of queue
            q.push_front(e.second);
           
          is_in_queue[e.second] = true;
        }
      }
    }
  }
  return distance;
}
 
// Driver Code
int main(int argc, char const *argv[])
{
   
  // Adjacency matrix of graph
  vector<vector<int>> graph = { { 0, 4, 0, 0, 8 },
                                { 0, 0, 8, 0, 11 },
                                { 0, 8, 0, 2, 0 },
                                { 0, 0, 2, 0, 1 },
                                { 8, 11, 0, 1, 0 } };
  for(auto i : desopo(graph))
  {
    cout << i << " ";
  }
  return 0;
}
 
// This code is contributed by sanjeev2552


Java




// Java implementation for
// D'Esopo-Pape algorithm
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
 
public class GFG {
 
  // Function to implement D'Esopo-Pape algorithm
  public static int[] desopo(int[][] graph) {
 
    // Number of vertices in graph
    int v = graph.length;
 
    // Adjacency list of graph
    List<Integer>[] adj = new List[v];
    for (int i = 0; i < v; i++) {
      for (int j = i + 1; j < v; j++) {
        if (graph[i][j] != 0) {
          if (adj[i] == null) adj[i] = new ArrayList<>();
          adj[i].add(graph[i][j]);
          adj[i].add(j);
          if (adj[j] == null) adj[j] = new ArrayList<>();
          adj[j].add(graph[i][j]);
          adj[j].add(i);
        }
      }
    }
 
    // Queue to store unoperated vertices
    List<Integer> q = new ArrayList<>();
 
    // Distance from source vertex
    int[] distance = new int[v];
    Arrays.fill(distance, Integer.MAX_VALUE);
 
    // Status of vertex
    boolean[] isInQueue = new boolean[v];
 
    // Let 0 be the source vertex
    int source = 0;
    distance = 0;
    q.add(source);
    isInQueue = true;
 
    while (!q.isEmpty()) {
 
      // Pop from front of the queue
      int u = q.get(0);
      q.remove(0);
      isInQueue[u] = false;
 
      // Scan adjacent vertices of u
      for (int i = 0; i < adj[u].size(); i += 2) {
 
        int e = adj[u].get(i + 1);
        if (distance[e] > distance[u] + adj[u].get(i)) {
          distance[e] = distance[u] + adj[u].get(i);
          if (!isInQueue[e]) {
 
            // If e is entering
            // first time in the queue
            if (distance[e] == Integer.MAX_VALUE)
 
              // Append at back of queue
              q.add(e);
            else
 
              // Append at front of queue
              q.add(0, e);
 
            isInQueue[e] = true;
          }
        }
      }
    }
    return distance;
  }
 
  // Adjacency matrix of graph
  static int[][] graph = {
    {0, 4, 0, 0, 8},
    {0, 0, 8, 0, 11},
    {0, 8, 0, 2, 0},
    {0, 0, 2, 0, 1},
    {8, 11, 0, 1, 0}
  };
 
  public static void main(String[] args) {
    System.out.println(Arrays.toString(desopo(graph)));
  }
}
 
// This code is contributed by ishankhandelwals.


Python3




# Python3 implementation for
# D'Esopo-Pape algorithm
 
from collections import defaultdict, deque
 
def desopo(graph):
    # Number of vertices in graph
    v = len(graph)
     
    # Adjacency list of graph
    adj = defaultdict(list)
    for i in range(v):
        for j in range(i + 1, v):
            if graph[i][j] != 0:
                adj[i].append(
                    [graph[i][j], j]
                )
                adj[j].append(
                    [graph[i][j], i]
                )
     
     
    # Queue to store unoperated vertices
    q = deque([])
     
    # Distance from source vertex
    distance =[float('inf')]*v
     
    # Status of vertex
    is_in_queue =[False]*v
     
    # let 0 be the source vertex
    source = 0
    distance= 0
    q.append(source)
    is_in_queue= True
     
    while q:
        # Pop from front of the queue
        u = q.popleft()
        is_in_queue[u]= False
     
        # scan adjacent vertices of u
        for e in adj[u]:
            # e <- [weight, vertex]
            if distance[e[1]] > distance[u]+e[0]:
                distance[e[1]]= distance[u]+e[0]
                if is_in_queue[e[1]]== False:
                    # if e[1] is entering
                    # first time in the queue
                    if distance[e[1]]== float('inf'):
                        # Append at back of queue
                        q.append(e[1])
                    else:
                        # Append at front of queue
                        q.appendleft(e[1])
                    is_in_queue[e[1]] = True
    return distance
 
 
# Driver Code
if __name__ == "__main__":
    # Adjacency matrix of graph
    graph = [[0, 4, 0, 0, 8],
            [0, 0, 8, 0, 11],
            [0, 8, 0, 2, 0],
            [0, 0, 2, 0, 1],
            [8, 11, 0, 1, 0]
            ]
    print(desopo(graph))


C#




// C# implementation for
// D'Esopo-Pape algorithm
using System;
using System.Collections.Generic;
using System.Linq;
namespace GFG {
  class Program
  {
 
    // Number of vertices in graph
    static int v;
 
    // Adjacency list of graph
    static Dictionary<int, List<Tuple<int, int> > > adj;
 
    // Queue to store unoperated vertices
    static Queue<int> q;
 
    // Distance from source vertex
    static int[] distance;
 
    // Status of vertex
    static bool[] is_in_queue;
 
    // let 0 be the source vertex
    static int source = 0;
    static List<int> desopo(int[, ] graph)
    {
 
      // Number of vertices in graph
      v = graph.GetLength(0);
 
      // Adjacency list of graph
      adj = new Dictionary<int,
      List<Tuple<int, int> > >();
      for (int i = 0; i < v; i++) {
        for (int j = i + 1; j < v; j++) {
          if (graph[i, j] != 0) {
            if (adj.ContainsKey(i)) {
              adj[i].Add(new Tuple<int, int>(
                graph[i, j], j));
            }
            else {
              adj.Add(
                i,
                new List<Tuple<int, int> >());
              adj[i].Add(new Tuple<int, int>(
                graph[i, j], j));
            }
            if (adj.ContainsKey(j)) {
              adj[j].Add(new Tuple<int, int>(
                graph[i, j], i));
            }
            else {
              adj.Add(
                j,
                new List<Tuple<int, int> >());
              adj[j].Add(new Tuple<int, int>(
                graph[i, j], i));
            }
          }
        }
      }
 
      // Queue to store unoperated vertices
      q = new Queue<int>();
 
      // Distance from source vertex
      distance = Enumerable.Repeat(Int32.MaxValue, v)
        .ToArray();
 
      // Status of vertex
      is_in_queue = new bool[v];
 
      // let 0 be the source vertex
      source = 0;
      distance = 0;
      q.Enqueue(source);
      is_in_queue = true;
      while (q.Count != 0)
      {
 
        // Pop from front of the queue
        int u = q.Dequeue();
        is_in_queue[u] = false;
 
        // Scan adjacent vertices of u
        foreach(var e in adj[u])
        {
          // e <- [weight, vertex]
          if (distance[e.Item2]
              > distance[u] + e.Item1) {
            distance[e.Item2]
              = distance[u] + e.Item1;
            if (!is_in_queue[e.Item2])
            {
 
 
              // if e.second is entering
              // first time in the queue
              if (distance[e.Item2]
                  == Int32.MaxValue)
 
                // Append at back of queue
                q.Enqueue(e.Item2);
              else
 
                // Append at front of queue
                q.Enqueue(e.Item2);
              is_in_queue[e.Item2] = true;
            }
          }
        }
      }
      return distance.ToList();
    }
 
    // Driver Code
    static void Main(string[] args)
    {
 
      // Adjacency matrix of graph
      int[, ] graph = { { 0, 4, 0, 0, 8 },
                       { 0, 0, 8, 0, 11 },
                       { 0, 8, 0, 2, 0 },
                       { 0, 0, 2, 0, 1 },
                       { 8, 11, 0, 1, 0 } };
      foreach(var i in desopo(graph))
      {
        Console.Write(i + " ");
      }
    }
  }
}
 
// This code is contributed by ishankhandelwals.


Javascript




// JavaScript implementation for
// D'Esopo-Pape algorithm
 
// Function to implement D'Esopo-Pape algorithm
function desopo(graph) {
 
  // Number of vertices in graph
  let v = graph.length;
 
  // Adjacency list of graph
  let adj = {};
  for (let i = 0; i < v; i++) {
    for (let j = i + 1; j < v; j++) {
      if (graph[i][j] !== 0) {
        if (!adj[i]) adj[i] = [];
        adj[i].push([graph[i][j], j]);
        if (!adj[j]) adj[j] = [];
        adj[j].push([graph[i][j], i]);
      }
    }
  }
 
  // Queue to store unoperated vertices
  let q = [];
 
  // Distance from source vertex
  let distance = new Array(v).fill(Number.MAX_SAFE_INTEGER);
 
  // Status of vertex
  let isInQueue = new Array(v).fill(false);
 
  // Let 0 be the source vertex
  let source = 0;
  distance = 0;
  q.push(source);
  isInQueue = true;
 
  while (q.length !== 0) {
 
    // Pop from front of the queue
    let u = q.shift();
    isInQueue[u] = false;
 
    // Scan adjacent vertices of u
    for (let e of adj[u]) {
 
      // e <- [weight, vertex]
      if (distance[e[1]] > distance[u] + e[0]) {
        distance[e[1]] = distance[u] + e[0];
        if (!isInQueue[e[1]]) {
 
          // If e[1] is entering
          // first time in the queue
          if (distance[e[1]] === Number.MAX_SAFE_INTEGER)
 
            // Append at back of queue
            q.push(e[1]);
          else
 
            // Append at front of queue
            q.unshift(e[1]);
 
          isInQueue[e[1]] = true;
        }
      }
    }
  }
  return distance;
}
 
// Adjacency matrix of graph
let graph = [  [0, 4, 0, 0, 8],
  [0, 0, 8, 0, 11],
  [0, 8, 0, 2, 0],
  [0, 0, 2, 0, 1],
  [8, 11, 0, 1, 0]
];
console.log(desopo(graph));
 
// This code is contributed by ishankhandelwals.


Output: 

[0, 4, 11, 9, 8]

 

Time Complexity: O(E log V), where E is the number of edges and V is the number of vertices in the graph. 

Space Complexity: O(V + E), since we need to store the adjacency list (which takes O(E) space) and additional arrays to store the distance from the source vertex, the status of each vertex, and the queue of unoperated vertices (which take O(V) space). Therefore, the overall space complexity is O(V + E).



Last Updated : 12 Apr, 2023
Like Article
Save Article
Previous
Next
Share your thoughts in the comments
Similar Reads