Skip to content
Related Articles

Related Articles

Monotonic shortest path from source to destination in Directed Weighted Graph

View Discussion
Improve Article
Save Article
  • Last Updated : 03 Aug, 2022
View Discussion
Improve Article
Save Article

Given a weighted directed graph with N vertices and M edges, a source src and a destination target, the task is to find the shortest monotonic path (monotonically increasing or decreasing) from the source to the destination. Output -1 if no monotonic path is possible.

Note: All weights are non-negative

Examples:

Input: N = 6, M = 9, src = 1, target = 2
edges = {{1, 3, 1.1}, {1, 5, 2}, {1, 6, 3.3}, {2, 5, 2.7},  
{3, 4, 2}, {3, 5, 1.1}, {4, 2, 2.3}, {5, 6, 2.4}, {6, 2, 3}}

Graph for first example

Graph for first example

Output: 5.4
Explanation: There are three monotonic paths in the graph 
that originate from vertex 1, which are 1 – 6 – 2 because it is strictly increasing,  
and 1 – 3 – 4 – 2, and 1 – 5 – 6 – 2 since both are strictly decreasing. 
The shortest one of these paths is 1 – 3 – 4 – 2,  
which has a sum of weights equal to 1.1 + 2 + 2.3 = 5.4,  
So the output is 5.4.

Input: N = 5, M = 5, src = 1, target = 5
edges = {{1, 2, 2.3}, {1, 3, 3.1}, {2, 3, 3.7}, {3, 4, 1.9}, {4, 5, 2.1}}

Graph for second example

Graph for second example

Output: -1
Explanation: No monotonic path exists from vertex 1 to vertex 5.

 

Approach: To solve the problem follow the below idea:

Run Dijkstra’s algorithm twice: one for increasing shortest paths and another for decreasing shortest paths, and take the shorter path of the two results. 

Follow the given steps to solve the problem:

  • Run Dijkstra’s algorithm twice for both increasing and decreasing paths.
    • While doing Dijkstra’s for decreasing shortest paths: 
      • Only update the shortest path to a vertex v from vertex u if the weight of the edge from u to v is less than the edge on the shortest path directed towards u
    • Similarly for the increasing shortest paths: 
      • Only update the shortest path to a vertex v from u, if the edge from u to v is greater than the edge on the shortest path directed towards u.
  • If the destination vertex has not yet been reached, then no valid shortest path exists. 
  • If both passes of Dijkstra’s on increasing and decreasing shortest paths result in no valid paths, then return -1.

Below is the implementation of the above approach.

Java




import java.io.*;
import java.util.*;
 
// Finds the monotonic shortest path
// using Dijkstra's algorithm
class Main {
    public static void main(String[] args)
    {
        int N = 6;
        int M = 9;
 
        // Create an array of vertices
        Vertex[] vertices = new Vertex[N + 1];
 
        // Create instances of each vertex from 1 to N
        for (int i = 1; i <= N; i++)
            vertices[i] = new Vertex(i);
 
        vertices[1].adjList.add(3);
        vertices[1].adjWeights.add(1.1);
 
        vertices[1].adjList.add(5);
        vertices[1].adjWeights.add(2.0);
 
        vertices[1].adjList.add(6);
        vertices[1].adjWeights.add(3.3);
 
        vertices[2].adjList.add(5);
        vertices[2].adjWeights.add(2.7);
 
        vertices[3].adjList.add(4);
        vertices[3].adjWeights.add(2.0);
 
        vertices[3].adjList.add(5);
        vertices[3].adjWeights.add(1.1);
 
        vertices[4].adjList.add(2);
        vertices[4].adjWeights.add(2.3);
 
        vertices[5].adjList.add(6);
        vertices[5].adjWeights.add(2.4);
 
        vertices[6].adjList.add(2);
        vertices[6].adjWeights.add(3.0);
 
        // Source and destination vertices
        int src = 1;
        int target = 2;
        System.out.println(
            shortestPath(vertices, N, src, target));
    }
 
    public static double shortestPath(Vertex vertices[],
                                      int N, int source,
                                      int destination)
    {
        // Stores distance from source and edge
        // on the shortest path from source
        double[] distTo = new double[N + 1];
        double[] edgeTo = new double[N + 1];
 
        // Set initial distance from source
        // to the highest value
        for (int i = 1; i <= N; i++)
            distTo[i] = Double.MAX_VALUE;
 
        // Monotonic decreasing pass of dijkstras
        distTo = 0.0;
        edgeTo = Double.MAX_VALUE;
 
        PriorityQueue<Vertex> pq
            = new PriorityQueue<Vertex>(
                new Comparator<Vertex>() {
                    public int compare(Vertex a, Vertex b)
                    {
                        return Double.compare(distTo[a.id],
                                              distTo[b.id]);
                    }
                });
 
        // Add the initial source vertex
        // into the priority queue
        pq.add(vertices);
 
        while (!pq.isEmpty()) {
 
            // Take the vertex with the closest
            // current distance from source
            Vertex closest = pq.remove();
 
            for (int i = 0; i < closest.adjList.size();
                 i++) {
 
                // Checks if the edges are decreasing and
                // whether the current directed edge will
                // create a shorter path
                if (closest.adjWeights.get(i)
                        < edgeTo[closest.id]
                    && distTo[closest.id]
                               + closest.adjWeights.get(i)
                           < distTo[closest.adjList.get(
                                 i)]) {
                    edgeTo[closest.adjList.get(i)]
                        = closest.adjWeights.get(i);
                    distTo[closest.adjList.get(i)]
                        = closest.adjWeights.get(i)
                          + distTo[closest.id];
                    pq.add(
                        vertices[closest.adjList.get(i)]);
                }
            }
        }
 
        // Store the result of the first pass of dijkstras
        double firstPass = distTo[destination];
 
        // Monotonic increasing pass of dijkstras
        for (int i = 1; i <= N; i++)
            distTo[i] = Double.MAX_VALUE;
        distTo = 0.0;
        edgeTo = 0.0;
 
        // Add the initial source vertex
        // into the priority queue
        pq.add(vertices);
 
        while (!pq.isEmpty()) {
 
            // Take the vertex with the closest current
            // distance from source
            Vertex closest = pq.remove();
 
            for (int i = 0; i < closest.adjList.size();
                 i++) {
 
                // Checks if the edges are increasing and
                // whether the current directed edge will
                // create a shorter path
                if (closest.adjWeights.get(i)
                        > edgeTo[closest.id]
                    && distTo[closest.id]
                               + closest.adjWeights.get(i)
                           < distTo[closest.adjList.get(
                                 i)]) {
                    edgeTo[closest.adjList.get(i)]
                        = closest.adjWeights.get(i);
                    distTo[closest.adjList.get(i)]
                        = closest.adjWeights.get(i)
                          + distTo[closest.id];
                    pq.add(
                        vertices[closest.adjList.get(i)]);
                }
            }
        }
 
        // Store the result of the second pass of Dijkstras
        double secondPass = distTo[destination];
 
        if (firstPass == Double.MAX_VALUE
            && secondPass == Double.MAX_VALUE)
            return -1;
        return Math.min(firstPass, secondPass);
    }
}
 
// Represents a vertex in the graph
// id stores the vertex number of the vertex instance
// adjList stores the id's of adjacent vertices
// adjWeights stores the weights of adjacent vertices with
// the same indexing as adjList
class Vertex {
    int id;
    ArrayList<Integer> adjList;
    ArrayList<Double> adjWeights;
 
    // A constructor which accepts
    // the id of the vertex
    public Vertex(int num)
    {
        id = num;
        adjList = new ArrayList<Integer>();
        adjWeights = new ArrayList<Double>();
    }
}

Output

5.4

Time Complexity: O(N log(N) + M)
Auxiliary Space: O(N)


My Personal Notes arrow_drop_up
Recommended Articles
Page :

Start Your Coding Journey Now!