Open In App

Widest Path Problem | Practical application of Dijkstra’s Algorithm

Improve
Improve
Like Article
Like
Save
Share
Report

It is highly recommended to read Dijkstra’s algorithm using the Priority Queue first.
Widest Path Problem is a problem of finding a path between two vertices of the graph maximizing the weight of the minimum-weight edge in the path. See the below image to get the idea of the problem:
 

Graph

Practical Application Example: 
This problem is a famous variant of Dijkstra’s algorithm. In the practical application, this problem can be seen as a graph with routers as its vertices and edges represent bandwidth between two vertices. Now if we want to find the maximum bandwidth path between two places in the internet connection, then this problem can be solved by this algorithm.
How to solve this problem? 
We are going to solve this problem by using the priority queue ((|E|+|V|)log|V|) implementation of the Dijkstra’s algorithm with a slight change.
We solve this problem by just replacing the condition of relaxation in Dijkstra’s algorithm by:
 

max(min(widest_dist[u], weight(u, v)), widest_dist[v])

where u is the source vertex for v. v is the current vertex we are checking the condition.
This algorithm runs for both directed and undirected graph.
See the series of images below to get the idea about the problem and the algorithm:
The values over the edges represents weights of directed edges. 
 

DAG

We will start from source vertex and then travel all the vertex connected to it and add in priority queue according to relaxation condition. 
 

 

Now (2, 1) will pop up and 2 will be the current source vertex.
 

Now (3, 1) will pop from the queue. But as 3 does not have any connected vertex through directed edge nothing will happen. So (4, 2) will pop next.
 

Finally the algorithm stops, as there is no more elements in priority queue. 
 

The path with the maximum value of widest distance is 1-4-3 which has the maximum bottle-neck value of 2. So we end up getting widest distance of 2 to reach the target vertex 3.
Below is the implementation of the above approach:
 

CPP




// C++ implementation of the approach
#include <bits/stdc++.h>
using namespace std;
 
// Function to print the required path
void printpath(vector<int>& parent, int vertex, int target)
{
    if (vertex == 0) {
        return;
    }
 
    printpath(parent, parent[vertex], target);
 
    cout << vertex << (vertex == target ? "\n" : "--");
}
 
// Function to return the maximum weight
// in the widest path of the given graph
int widest_path_problem(vector<vector<pair<int, int> > >& Graph,
                        int src, int target)
{
    // To keep track of widest distance
    vector<int> widest(Graph.size(), INT_MIN);
 
    // To get the path at the end of the algorithm
    vector<int> parent(Graph.size(), 0);
 
    // Use of Minimum Priority Queue to keep track minimum
    // widest distance vertex so far in the algorithm
    priority_queue<pair<int, int>, vector<pair<int, int> >,
                   greater<pair<int, int> > >
        container;
 
    container.push(make_pair(0, src));
 
    widest[src] = INT_MAX;
 
    while (container.empty() == false) {
        pair<int, int> temp = container.top();
 
        int current_src = temp.second;
 
        container.pop();
 
        for (auto vertex : Graph[current_src]) {
 
            // Finding the widest distance to the vertex
            // using current_source vertex's widest distance
            // and its widest distance so far
            int distance = max(widest[vertex.second],
                               min(widest[current_src], vertex.first));
 
            // Relaxation of edge and adding into Priority Queue
            if (distance > widest[vertex.second]) {
 
                // Updating bottle-neck distance
                widest[vertex.second] = distance;
 
                // To keep track of parent
                parent[vertex.second] = current_src;
 
                // Adding the relaxed edge in the priority queue
                container.push(make_pair(distance, vertex.second));
            }
        }
    }
 
    printpath(parent, target, target);
 
    return widest[target];
}
 
// Driver code
int main()
{
 
    // Graph representation
    vector<vector<pair<int, int> > > graph;
 
    int no_vertices = 4;
 
    graph.assign(no_vertices + 1, vector<pair<int, int> >());
 
    // Adding edges to graph
 
    // Resulting graph
    // 1--2
    // |  |
    // 4--3
 
    // Note that order in pair is (distance, vertex)
    graph[1].push_back(make_pair(1, 2));
    graph[1].push_back(make_pair(2, 4));
    graph[2].push_back(make_pair(3, 3));
    graph[4].push_back(make_pair(5, 3));
 
    cout << widest_path_problem(graph, 1, 3);
 
    return 0;
}


Java




/*package whatever //do not write package name here */
import java.io.*;
import java.util.*;
 
// Java implementation of the approach
class iPair {
  int first, second;
 
  iPair(int first, int second) {
    this.first = first;
    this.second = second;
  }
}
 
public class Main {
 
  // Function to print the required path
  public static void printpath(int[] parent, int vertex, int target)
  {
    if (vertex == 0) {
      return;
    }
 
    printpath(parent, parent[vertex], target);
 
    System.out.print(vertex + (vertex == target ? "\n" : "--"));
  }
 
  // Function to return the maximum weight
  // in the widest path of the given graph
  public static int widest_path_problem(List<List<iPair>> Graph, int src, int target, int no_vertices)
  {
    // To keep track of widest distance
    int[] widest=new int[Graph.size()];
    Arrays.fill(widest, Integer.MIN_VALUE);
 
    int[] parent = new int[Graph.size()];
    Arrays.fill(parent, 0);
 
    // Use of Minimum Priority Queue to keep track minimum
    // widest distance vertex so far in the algorithm
    PriorityQueue<iPair> container = new PriorityQueue<>(no_vertices+1, Comparator.comparingInt(o -> o.first));
    container.add(new iPair(0, src));
 
    widest[src] = Integer.MAX_VALUE;
 
    while (!container.isEmpty()) {
      iPair temp = container.poll();
 
      int current_src = temp.second;
 
      for (iPair vertex : Graph.get(current_src)) {
 
        // Finding the widest distance to the vertex
        // using current_source vertex's widest distance
        // and its widest distance so far
        int distance = Math.max(widest[vertex.second], Math.min(widest[current_src], vertex.first));
 
        // Relaxation of edge and adding into Priority Queue
        if (distance > widest[vertex.second]) {
 
          // Updating bottle-neck distance
          widest[vertex.second] = distance;
 
          // To keep track of parent
          parent[vertex.second] = current_src;
 
          // Adding the relaxed edge in the priority queue
          container.add(new iPair(distance, vertex.second));
        }
      }
    }
 
    printpath(parent, target, target);
 
    return widest[target];
  }
 
  public static void main(String[] args) {
    // Graph representation
    List<List<iPair>> graph = new ArrayList<>();
    int no_vertices = 4;
 
    for(int i = 0; i < no_vertices + 1; i++){
      graph.add(new ArrayList<>());
    }
 
    // Adding edges to graph
 
    // Resulting graph
    // 1--2
    // |  |
    // 4--3
 
    // Note that order in pair is (distance, vertex)
    graph.get(1).add(new iPair(1, 2));
    graph.get(1).add(new iPair(2, 4));
    graph.get(2).add(new iPair(3, 3));
    graph.get(4).add(new iPair(5, 3));
 
    System.out.println(widest_path_problem(graph, 1, 3, no_vertices));
  }
}
 
// The code is contributed by Arushi Jindal.


Python3




# Python3 implementation of the approach
 
# Function to print required path
def printpath(parent, vertex, target):
     
    # global parent
    if (vertex == 0):
        return
    printpath(parent, parent[vertex], target)
    print(vertex ,end="\n" if (vertex == target) else "--")
 
# Function to return the maximum weight
# in the widest path of the given graph
def widest_path_problem(Graph, src, target):
     
    # To keep track of widest distance
    widest = [-10**9]*(len(Graph))
 
    # To get the path at the end of the algorithm
    parent = [0]*len(Graph)
 
    # Use of Minimum Priority Queue to keep track minimum
    # widest distance vertex so far in the algorithm
    container = []
    container.append((0, src))
    widest[src] = 10**9
    container = sorted(container)
    while (len(container)>0):
        temp = container[-1]
        current_src = temp[1]
        del container[-1]
        for vertex in Graph[current_src]:
 
            # Finding the widest distance to the vertex
            # using current_source vertex's widest distance
            # and its widest distance so far
            distance = max(widest[vertex[1]],
                           min(widest[current_src], vertex[0]))
 
            # Relaxation of edge and adding into Priority Queue
            if (distance > widest[vertex[1]]):
 
                # Updating bottle-neck distance
                widest[vertex[1]] = distance
 
                # To keep track of parent
                parent[vertex[1]] = current_src
 
                # Adding the relaxed edge in the priority queue
                container.append((distance, vertex[1]))
                container = sorted(container)
    printpath(parent, target, target)
    return widest[target]
 
# Driver code
if __name__ == '__main__':
 
    # Graph representation
    graph = [[] for i in range(5)]
    no_vertices = 4
    # Adding edges to graph
 
    # Resulting graph
    #1--2
    #|  |
    #4--3
 
    # Note that order in pair is (distance, vertex)
    graph[1].append((1, 2))
    graph[1].append((2, 4))
    graph[2].append((3, 3))
    graph[4].append((5, 3))
 
    print(widest_path_problem(graph, 1, 3))
 
# This code is contributed by mohit kumar 29


C#




using System;
using System.Collections.Generic;
 
class Program
{
  static int V = 5;
   
  // Function to print required path
  static void PrintPath(int[] parent, int vertex, int target)
  {
    // global parent
    if (vertex == 0)
    {
      return;
    }
    PrintPath(parent, parent[vertex], target);
    Console.Write(vertex + (vertex == target ? "\n" : "--"));
  }
   
  // Function to return the maximum weight
  // in the widest path of the given graph
  static int WidestPathProblem(List<Tuple<int, int>>[] Graph, int src, int target)
  {
    int[] widest = new int[V];
    for (int i = 0; i < V; i++)
    {
      widest[i] = -1000000000;
    }
     
    // To get the path at the end of the algorithm
    int[] parent = new int[V];
 
    List<Tuple<int, int>> container = new List<Tuple<int, int>>();
     
    // Use of Minimum Priority Queue to keep track minimum
    // widest distance vertex so far in the algorithm
    container.Add(new Tuple<int, int>(0, src));
    widest[src] = 1000000000;
    container.Sort((x, y) => y.Item1.CompareTo(x.Item1));
 
    while (container.Count > 0)
    {
      Tuple<int, int> temp = container[container.Count - 1];
      int current_src = temp.Item2;
      container.RemoveAt(container.Count - 1);
 
      foreach (Tuple<int, int> vertex in Graph[current_src])
      {
        // Finding the widest distance to the vertex
        // using current_source vertex's widest distance
        // and its widest distance so far
        int distance = Math.Max(widest[vertex.Item2], Math.Min(widest[current_src], vertex.Item1));
        // Relaxation of edge and adding into Priority Queue
        if (distance > widest[vertex.Item2])
        {
          widest[vertex.Item2] = distance;
          parent[vertex.Item2] = current_src;
          container.Add(new Tuple<int, int>(distance, vertex.Item2));
          container.Sort((x, y) => y.Item1.CompareTo(x.Item1));
        }
      }
    }
    PrintPath(parent, target, target);
    return widest[target];
  }
  //Driver code
  static void Main(string[] args)
  {
    List<Tuple<int, int>>[] graph = new List<Tuple<int, int>>[V];
    int no_vertices = 4;
 
    for (int i = 0; i < V; i++)
    {
      graph[i] = new List<Tuple<int, int>>();
    }
 
    graph[1].Add(new Tuple<int, int>(1, 2));
    graph[1].Add(new Tuple<int, int>(2, 4));
    graph[2].Add(new Tuple<int, int>(3, 3));
    graph[4].Add(new Tuple<int, int>(5, 3));
 
    Console.WriteLine(WidestPathProblem(graph, 1, 3));
  }
}


Javascript




// Function to print required path
function printpath(parent, vertex, target) {
  let output = "";
  if (vertex === 0) {
    return "";
  }
  output += printpath(parent, parent[vertex], target);
  output += vertex + (vertex === target ? "\n" : "--");
  return output;
}
 
// Function to return the maximum weight
// in the widest path of the given graph
function widest_path_problem(Graph, src, target) {
  // To keep track of widest distance
  let widest = Array(Graph.length).fill(-1e9);
 
  // To get the path at the end of the algorithm
  let parent = Array(Graph.length).fill(0);
 
  // Use of Minimum Priority Queue to keep track minimum
  // widest distance vertex so far in the algorithm
  let container = [];
  container.push([0, src]);
  widest[src] = 1e9;
  container.sort((a, b) => b[0] - a[0]);
  while (container.length > 0) {
    let temp = container[container.length - 1];
    let current_src = temp[1];
    container.pop();
    for (let i = 0; i < Graph[current_src].length; i++) {
      let vertex = Graph[current_src][i];
      // Finding the widest distance to the vertex
      // using current_source vertex's widest distance
      // and its widest distance so far
      let distance = Math.max(
        widest[vertex[1]],
        Math.min(widest[current_src], vertex[0])
      );
 
      // Relaxation of edge and adding into Priority Queue
      if (distance > widest[vertex[1]]) {
        // Updating bottle-neck distance
        widest[vertex[1]] = distance;
 
        // To keep track of parent
        parent[vertex[1]] = current_src;
 
        // Adding the relaxed edge in the priority queue
        container.push([distance, vertex[1]]);
        container.sort((a, b) => b[0] - a[0]);
      }
    }
  }
  let path = printpath(parent, target, target);
  console.log(path);
  return widest[target];
}
 
// Driver code
let graph = [[], [], [], [], []];
let no_vertices = 4;
// Adding edges to graph
 
// Resulting graph
//1--2
//| |
//4--3
 
// Note that order in pair is (distance, vertex)
graph[1].push([1, 2]);
graph[1].push([2, 4]);
graph[2].push([3, 3]);
graph[4].push([5, 3]);
 
console.log(widest_path_problem(graph, 1, 3));


Output: 

1--4--3
2

 

Time Complexity: O(E * logV), Where E is the total number of edges and V is the total number of vertices in the graph.
Auxiliary Space: O(V).  



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