Longest Path in a Directed Acyclic Graph - GeeksforGeeks

13 Sep, 2021
Given a Weighted Directed Acyclic Graph (DAG) and a source vertex s in it, find the longest distances from s to all other vertices in the given graph.The longest path problem for a general graph is not as easy as the shortest path problem because the longest path problem doesn’t have optimal substructure property. In fact, the Longest Path problem is NP-Hard for a general graph. However, the longest path problem has a linear time solution for directed acyclic graphs. The idea is similar to linear time solution for shortest path in a directed acyclic graph., we use Topological Sorting. We initialize distances to all vertices as minus infinite and distance to source as 0, then we find a topological sorting of the graph. Topological Sorting of a graph represents a linear ordering of the graph (See below, figure (b) is a linear representation of figure (a) ). Once we have topological order (or linear representation), we one by one process all vertices in topological order. For every vertex being processed, we update distances of its adjacent using distance of current vertex.Following figure shows step by step process of finding longest paths. 
Following is complete algorithm for finding longest distances. 1) Initialize dist[] = {NINF, NINF, ....} and dist[s] = 0 where s is the source vertex. Here NINF means negative infinite. 2) Create a topological order of all vertices. 3) Do following for every vertex u in topological order. ...........Do following for every adjacent vertex v of u ..................if (dist[v] < dist[u] + weight(u, v)) ...........................dist[v] = dist[u] + weight(u, v)  
Following is C++ implementation of the above algorithm. 
CPP
Java
Python3
// A C++ program to find single source longest distances// in a DAG#include <iostream>#include <limits.h>#include <list>#include <stack>#define NINF INT_MINusing namespace std; // Graph is represented using adjacency list. Every// node of adjacency list contains vertex number of// the vertex to which edge connects. It also// contains weight of the edgeclass AdjListNode {    int v;    int weight;   public:    AdjListNode(int _v, int _w)    {        v = _v;        weight = _w;    }    int getV() { return v; }    int getWeight() { return weight; }};   // Class to represent a graph using adjacency list// representationclass Graph {    int V; // No. of vertices'       // Pointer to an array containing adjacency lists    list<AdjListNode>* adj;       // A function used by longestPath    void topologicalSortUtil(int v, bool visited[],                             stack<int>& Stack);   public:    Graph(int V); // Constructor    ~Graph(); // Destructor     // function to add an edge to graph    void addEdge(int u, int v, int weight);       // Finds longest distances from given source vertex    void longestPath(int s);};   Graph::Graph(int V) // Constructor{    this->V = V;    adj = new list<AdjListNode>[V];} Graph::~Graph() // Destructor{    delete [] adj;}  void Graph::addEdge(int u, int v, int weight){    AdjListNode node(v, weight);    adj[u].push_back(node); // Add v to u's list}   // A recursive function used by longestPath. See below// link for details// https:// www.geeksforgeeks.org/topological-sorting/void Graph::topologicalSortUtil(int v, bool visited[],                                stack<int>& Stack){    // Mark the current node as visited    visited[v] = true;       // Recur for all the vertices adjacent to this vertex    list<AdjListNode>::iterator i;    for (i = adj[v].begin(); i != adj[v].end(); ++i) {        AdjListNode node = *i;        if (!visited[node.getV()])            topologicalSortUtil(node.getV(), visited, Stack);    }       // Push current vertex to stack which stores topological    // sort    Stack.push(v);}   // The function to find longest distances from a given vertex.// It uses recursive topologicalSortUtil() to get topological// sorting.void Graph::longestPath(int s){    stack<int> Stack;    int dist[V];       // Mark all the vertices as not visited    bool* visited = new bool[V];    for (int i = 0; i < V; i++)        visited[i] = false;       // Call the recursive helper function to store Topological    // Sort starting from all vertices one by one    for (int i = 0; i < V; i++)        if (visited[i] == false)            topologicalSortUtil(i, visited, Stack);       // Initialize distances to all vertices as infinite and    // distance to source as 0    for (int i = 0; i < V; i++)        dist[i] = NINF;    dist[s] = 0;    // Process vertices in topological order    while (Stack.empty() == false) {        // Get the next vertex from topological order        int u = Stack.top();        Stack.pop();           // Update distances of all adjacent vertices        list<AdjListNode>::iterator i;        if (dist[u] != NINF) {            for (i = adj[u].begin(); i != adj[u].end(); ++i){                             if (dist[i->getV()] < dist[u] + i->getWeight())                    dist[i->getV()] = dist[u] + i->getWeight();            }        }    }       // Print the calculated longest distances    for (int i = 0; i < V; i++)        (dist[i] == NINF) ? cout << "INF " : cout << dist[i] << " ";         delete [] visited;}   // Driver program to test above functionsint main(){    // Create a graph given in the above diagram.    // Here vertex numbers are 0, 1, 2, 3, 4, 5 with    // following mappings:    // 0=r, 1=s, 2=t, 3=x, 4=y, 5=z    Graph g(6);    g.addEdge(0, 1, 5);    g.addEdge(0, 2, 3);    g.addEdge(1, 3, 6);    g.addEdge(1, 2, 2);    g.addEdge(2, 4, 4);    g.addEdge(2, 5, 2);    g.addEdge(2, 3, 7);    g.addEdge(3, 5, 1);    g.addEdge(3, 4, -1);    g.addEdge(4, 5, -2);       int s = 1;    cout << "Following are longest distances from "            "source vertex "         << s << " \n";    g.longestPath(s);       return 0;}
// A Java program to find single source longest distances// in a DAGimport java.util.*;class GFG{     // Graph is represented using adjacency list. Every  // node of adjacency list contains vertex number of  // the vertex to which edge connects. It also  // contains weight of the edge  static class AdjListNode {    int v;    int weight;     AdjListNode(int _v, int _w)    {      v = _v;      weight = _w;    }    int getV() { return v; }    int getWeight() { return weight; }  }   // Class to represent a graph using adjacency list  // representation  static class Graph {    int V; // No. of vertices'     // Pointer to an array containing adjacency lists    ArrayList<ArrayList<AdjListNode>> adj;     Graph(int V) // Constructor    {      this.V = V;      adj = new ArrayList<ArrayList<AdjListNode>>(V);       for(int i = 0; i < V; i++){        adj.add(new ArrayList<AdjListNode>());      }    }     void addEdge(int u, int v, int weight)    {      AdjListNode node = new AdjListNode(v, weight);      adj.get(u).add(node); // Add v to u's list    }     // A recursive function used by longestPath. See below    // link for details    // https:// www.geeksforgeeks.org/topological-sorting/    void topologicalSortUtil(int v, boolean visited[],                             Stack<Integer> stack)    {      // Mark the current node as visited      visited[v] = true;       // Recur for all the vertices adjacent to this vertex      for (int i = 0; i<adj.get(v).size(); i++) {        AdjListNode node = adj.get(v).get(i);        if (!visited[node.getV()])          topologicalSortUtil(node.getV(), visited, stack);      }       // Push current vertex to stack which stores topological      // sort      stack.push(v);    }     // The function to find longest distances from a given vertex.    // It uses recursive topologicalSortUtil() to get topological    // sorting.    void longestPath(int s)    {      Stack<Integer> stack = new Stack<Integer>();      int dist[] = new int[V];       // Mark all the vertices as not visited      boolean visited[] = new boolean[V];      for (int i = 0; i < V; i++)        visited[i] = false;       // Call the recursive helper function to store Topological      // Sort starting from all vertices one by one      for (int i = 0; i < V; i++)        if (visited[i] == false)          topologicalSortUtil(i, visited, stack);       // Initialize distances to all vertices as infinite and      // distance to source as 0      for (int i = 0; i < V; i++)        dist[i] = Integer.MIN_VALUE;       dist[s] = 0;             // Process vertices in topological order      while (stack.isEmpty() == false)      {                 // Get the next vertex from topological order        int u = stack.peek();        stack.pop();         // Update distances of all adjacent vertices ;        if (dist[u] != Integer.MIN_VALUE)        {          for (int i = 0; i<adj.get(u).size(); i++)          {            AdjListNode node = adj.get(u).get(i);            if (dist[node.getV()] < dist[u] + node.getWeight())              dist[node.getV()] = dist[u] + node.getWeight();          }        }      }       // Print the calculated longest distances      for (int i = 0; i < V; i++)        if(dist[i] == Integer.MIN_VALUE)          System.out.print("INF ");      else        System.out.print(dist[i] + " ");    }  }   // Driver program to test above functions  public static void main(String args[])  {    // Create a graph given in the above diagram.    // Here vertex numbers are 0, 1, 2, 3, 4, 5 with    // following mappings:    // 0=r, 1=s, 2=t, 3=x, 4=y, 5=z    Graph g = new Graph(6);    g.addEdge(0, 1, 5);    g.addEdge(0, 2, 3);    g.addEdge(1, 3, 6);    g.addEdge(1, 2, 2);    g.addEdge(2, 4, 4);    g.addEdge(2, 5, 2);    g.addEdge(2, 3, 7);    g.addEdge(3, 5, 1);    g.addEdge(3, 4, -1);    g.addEdge(4, 5, -2);     int s = 1;    System.out.print("Following are longest distances from source vertex "+ s + " \n" );    g.longestPath(s);   }} // This code is contribute by adityapande88.
# A recursive function used by longestPath. See below# link for details# https:#www.geeksforgeeks.org/topological-sorting/def topologicalSortUtil(v):    global Stack, visited, adj    visited[v] = True     # Recur for all the vertices adjacent to this vertex    # list<AdjListNode>::iterator i    for i in adj[v]:        if (not visited[i[0]]):            topologicalSortUtil(i[0])     # Push current vertex to stack which stores topological    # sort    Stack.append(v) # The function to find longest distances from a given vertex.# It uses recursive topologicalSortUtil() to get topological# sorting.def longestPath(s):    global Stack, visited, adj, V    dist = [-10**9 for i in range(V)]     # Call the recursive helper function to store Topological    # Sort starting from all vertices one by one    for i in range(V):        if (visited[i] == False):            topologicalSortUtil(i)    # print(Stack)     # Initialize distances to all vertices as infinite and    # distance to source as 0    dist[s] = 0    # Stack.append(1)     # Process vertices in topological order    while (len(Stack) > 0):               # Get the next vertex from topological order        u = Stack[-1]        del Stack[-1]        #print(u)         # Update distances of all adjacent vertices        # list<AdjListNode>::iterator i        if (dist[u] != 10**9):            for i in adj[u]:                # print(u, i)                if (dist[i[0]] < dist[u] + i[1]):                    dist[i[0]] = dist[u] + i[1]     # Print calculated longest distances    # print(dist)    for i in range(V):        print("INF ",end="") if (dist[i] == -10**9) else print(dist[i],end=" ") # Driver codeif __name__ == '__main__':    V, Stack, visited = 6, [], [False for i in range(7)]    adj = [[] for i in range(7)]         # Create a graph given in the above diagram.    # Here vertex numbers are 0, 1, 2, 3, 4, 5 with    # following mappings:    # 0=r, 1=s, 2=t, 3=x, 4=y, 5=z    adj[0].append([1, 5])    adj[0].append([2, 3])    adj[1].append([3, 6])    adj[1].append([2, 2])    adj[2].append([4, 4])    adj[2].append([5, 2])    adj[2].append([3, 7])    adj[3].append([5, 1])    adj[3].append([4, -1])    adj[4].append([5, -2])     s = 1    print("Following are longest distances from source vertex ",s)    longestPath(s)     # This code is contributed by mohit kumar 29.
Output: 
Following are longest distances from source vertex 1
INF 0 2 9 8 10
Time Complexity: Time complexity of topological sorting is O(V+E). After finding topological order, the algorithm process all vertices and for every vertex, it runs a loop for all adjacent vertices. Total adjacent vertices in a graph is O(E). So the inner loop runs O(V+E) times. Therefore, overall time complexity of this algorithm is O(V+E).Exercise: The above solution print longest distances, extend the code to print paths also.  
Please write comments if you find anything incorrect, or you want to share more information about the topic discussed above 
Rohit0803
pranith maddineni
joelm
mohit kumar 29
adityapande88
surindertarika1234
khushboogoyal499
anikaseth98
Microfocus
Shortest Path
Topological Sorting
Graph
Graph
Shortest Path
Writing code in comment?
Please use ide.geeksforgeeks.org,
generate link and share the link here.
Bellman–Ford Algorithm | DP-23
Floyd Warshall Algorithm | DP-16
Travelling Salesman Problem | Set 1 (Naive and Dynamic Programming)
Traveling Salesman Problem (TSP) Implementation
Ford-Fulkerson Algorithm for Maximum Flow Problem
Shortest path in an unweighted graph
Strongly Connected Components
Union-Find Algorithm | Set 2 (Union By Rank and Path Compression)
Best First Search (Informed Search)
Find the number of islands | Set 1 (Using DFS)