Skip to content
geeksforgeeks
  • Courses
    • DSA to Development
    • Get IBM Certification
    • Newly Launched!
      • Master Django Framework
      • Become AWS Certified
    • For Working Professionals
      • Interview 101: DSA & System Design
      • Data Science Training Program
      • JAVA Backend Development (Live)
      • DevOps Engineering (LIVE)
      • Data Structures & Algorithms in Python
    • For Students
      • Placement Preparation Course
      • Data Science (Live)
      • Data Structure & Algorithm-Self Paced (C++/JAVA)
      • Master Competitive Programming (Live)
      • Full Stack Development with React & Node JS (Live)
    • Full Stack Development
    • Data Science Program
    • All Courses
  • Tutorials
    • Data Structures & Algorithms
    • ML & Data Science
    • Interview Corner
    • Programming Languages
    • Web Development
    • CS Subjects
    • DevOps And Linux
    • School Learning
  • Practice
    • Build your AI Agent
    • GfG 160
    • Problem of the Day
    • Practice Coding Problems
    • GfG SDE Sheet
  • Contests
    • Accenture Hackathon (Ending Soon!)
    • GfG Weekly [Rated Contest]
    • Job-A-Thon Hiring Challenge
    • All Contests and Events
  • DSA
  • Interview Problems on Graph
  • Practice Graph
  • MCQs on Graph
  • Graph Tutorial
  • Graph Representation
  • Graph Properties
  • Types of Graphs
  • Graph Applications
  • BFS on Graph
  • DFS on Graph
  • Graph VS Tree
  • Transpose Graph
  • Dijkstra's Algorithm
  • Minimum Spanning Tree
  • Prim’s Algorithm
  • Topological Sorting
  • Floyd Warshall Algorithm
  • Strongly Connected Components
  • Advantages & Disadvantages
Open In App
Next Article:
Max Area of Island - Largest in Boolean Matrix
Next article icon

Dinic’s algorithm for Maximum Flow

Last Updated : 13 Mar, 2023
Comments
Improve
Suggest changes
Like Article
Like
Report

Problem Statement : 
Given a graph that represents a flow network where every edge has a capacity. Also given two vertices source ‘s’ and sink ‘t’ in the graph, find the maximum possible flow from s to t with the following constraints :  

  1. Flow on an edge doesn’t exceed the given capacity of the edge.
  2. An incoming flow is equal to an outgoing flow for every vertex except s and t.

For example: 

In the following input graph, 

Dinic's algorithm for Maximum Flow 1

the maximum s-t flow is 19 which is shown below. 

 

Background : 

  1. Max Flow Problem Introduction: We introduced the Maximum Flow problem, discussed Greedy Algorithm, and introduced the residual graph.
  2. Ford-Fulkerson Algorithm and Edmond Karp Implementation: We discussed the Ford-Fulkerson algorithm and its implementation. We also discussed the residual graph in detail.

The time complexity of Edmond Karp Implementation is O(VE2). In this post, a new Dinic’s algorithm is discussed which is a faster algorithm and takes O(EV2).

Like Edmond Karp’s algorithm, Dinic’s algorithm uses following concepts : 

  1. A flow is maximum if there is no s to t path in residual graph.
  2. BFS is used in a loop. There is a difference though in the way we use BFS in both algorithms.

In Edmond’s Karp algorithm, we use BFS to find an augmenting path and send flow across this path. In Dinic’s algorithm, we use BFS to check if more flow is possible and to construct level graph. In level graph, we assign levels to all nodes, level of a node is shortest distance (in terms of number of edges) of the node from source. Once level graph is constructed, we send multiple flows using this level graph. This is the reason it works better than Edmond Karp. In Edmond Karp, we send only flow that is send across the path found by BFS.

Outline of Dinic’s algorithm : 

  1. Initialize residual graph G as given graph.
  2. Do BFS of G to construct a level graph (or assign levels to vertices) and also check if more flow is possible.
    1. If more flow is not possible, then return
    2. Send multiple flows in G using level graph until blocking flow is reached. 
      Here using level graph means, in every flow, levels of path nodes should be 0, 1, 2…(in order) from s to t.

A flow is Blocking Flow if no more flow can be sent using level graph, i.e., no more s-t path exists such that path vertices have current levels 0, 1, 2… in order. Blocking Flow can be seen same as maximum flow path in Greedy algorithm discussed here.

Illustration : 
Initial Residual Graph (Same as given Graph) 
 

Initial Residual Graph

Total Flow = 0

First Iteration : We assign levels to all nodes using BFS. We also check if more flow is possible (or there is a s-t path in residual graph). 
 

First Iteration

Now we find blocking flow using levels (means every flow path should have levels as 0, 1, 2, 3). We send three flows together. This is where it is optimized compared to Edmond Karp where we send one flow at a time. 
4 units of flow on path s – 1 – 3 – t. 
6 units of flow on path s – 1 – 4 – t. 
4 units of flow on path s – 2 – 4 – t. 
Total flow = Total flow + 4 + 6 + 4 = 14
After one iteration, residual graph changes to following. 
 

 residual graph after first iteration

Second Iteration : We assign new levels to all nodes using BFS of above modified residual graph. We also check if more flow is possible (or there is a s-t path in residual graph). 

Second Iteration

Now we find blocking flow using levels (means every flow path should have levels as 0, 1, 2, 3, 4). We can send only one flow this time. 
5 units of flow on path s – 2 – 4 – 3 – t 
Total flow = Total flow + 5 = 19
The new residual graph is 
 

Rssidual graph after Second Iteration

Third Iteration : We run BFS and create a level graph. We also check if more flow is possible and proceed only if possible. This time there is no s-t path in residual graph, so we terminate the algorithm.

Implementation : 
Below is c++ implementation of Dinic’s algorithm:  

CPP




// C++ implementation of Dinic's Algorithm
#include <bits/stdc++.h>
using namespace std;
 
// A structure to represent a edge between
// two vertex
struct Edge {
    int v; // Vertex v (or "to" vertex)
           // of a directed edge u-v. "From"
           // vertex u can be obtained using
           // index in adjacent array.
 
    int flow; // flow of data in edge
 
    int C; // capacity
 
    int rev; // To store index of reverse
             // edge in adjacency list so that
             // we can quickly find it.
};
 
// Residual Graph
class Graph {
    int V; // number of vertex
    int* level; // stores level of a node
    vector<Edge>* adj;
 
public:
    Graph(int V)
    {
        adj = new vector<Edge>[V];
        this->V = V;
        level = new int[V];
    }
 
    // add edge to the graph
    void addEdge(int u, int v, int C)
    {
        // Forward edge : 0 flow and C capacity
        Edge a{ v, 0, C, (int)adj[v].size() };
 
        // Back edge : 0 flow and 0 capacity
        Edge b{ u, 0, 0, (int)adj[u].size() };
 
        adj[u].push_back(a);
        adj[v].push_back(b); // reverse edge
    }
 
    bool BFS(int s, int t);
    int sendFlow(int s, int flow, int t, int ptr[]);
    int DinicMaxflow(int s, int t);
};
 
// Finds if more flow can be sent from s to t.
// Also assigns levels to nodes.
bool Graph::BFS(int s, int t)
{
    for (int i = 0; i < V; i++)
        level[i] = -1;
 
    level[s] = 0; // Level of source vertex
 
    // Create a queue, enqueue source vertex
    // and mark source vertex as visited here
    // level[] array works as visited array also.
    list<int> q;
    q.push_back(s);
 
    vector<Edge>::iterator i;
    while (!q.empty()) {
        int u = q.front();
        q.pop_front();
        for (i = adj[u].begin(); i != adj[u].end(); i++) {
            Edge& e = *i;
            if (level[e.v] < 0 && e.flow < e.C) {
                // Level of current vertex is,
                // level of parent + 1
                level[e.v] = level[u] + 1;
 
                q.push_back(e.v);
            }
        }
    }
 
    // IF we can not reach to the sink we
    // return false else true
    return level[t] < 0 ? false : true;
}
 
// A DFS based function to send flow after BFS has
// figured out that there is a possible flow and
// constructed levels. This function called multiple
// times for a single call of BFS.
// flow : Current flow send by parent function call
// start[] : To keep track of next edge to be explored.
//           start[i] stores  count of edges explored
//           from i.
//  u : Current vertex
//  t : Sink
int Graph::sendFlow(int u, int flow, int t, int start[])
{
    // Sink reached
    if (u == t)
        return flow;
 
    // Traverse all adjacent edges one -by - one.
    for (; start[u] < adj[u].size(); start[u]++) {
        // Pick next edge from adjacency list of u
        Edge& e = adj[u][start[u]];
 
        if (level[e.v] == level[u] + 1 && e.flow < e.C) {
            // find minimum flow from u to t
            int curr_flow = min(flow, e.C - e.flow);
 
            int temp_flow
                = sendFlow(e.v, curr_flow, t, start);
 
            // flow is greater than zero
            if (temp_flow > 0) {
                // add flow  to current edge
                e.flow += temp_flow;
 
                // subtract flow from reverse edge
                // of current edge
                adj[e.v][e.rev].flow -= temp_flow;
                return temp_flow;
            }
        }
    }
 
    return 0;
}
 
// Returns maximum flow in graph
int Graph::DinicMaxflow(int s, int t)
{
    // Corner case
    if (s == t)
        return -1;
 
    int total = 0; // Initialize result
 
    // Augment the flow while there is path
    // from source to sink
    while (BFS(s, t) == true) {
        // store how many edges are visited
        // from V { 0 to V }
        int* start = new int[V + 1]{ 0 };
 
        // while flow is not zero in graph from S to D
        while (int flow = sendFlow(s, INT_MAX, t, start)) {
 
            // Add path flow to overall flow
            total += flow;
        }
       
          // Remove allocated array
          delete[] start;
    }
 
    // return maximum flow
    return total;
}
 
// Driver Code
int main()
{
    Graph g(6);
    g.addEdge(0, 1, 16);
    g.addEdge(0, 2, 13);
    g.addEdge(1, 2, 10);
    g.addEdge(1, 3, 12);
    g.addEdge(2, 1, 4);
    g.addEdge(2, 4, 14);
    g.addEdge(3, 2, 9);
    g.addEdge(3, 5, 20);
    g.addEdge(4, 3, 7);
    g.addEdge(4, 5, 4);
 
    // next exmp
    /*g.addEdge(0, 1, 3 );
      g.addEdge(0, 2, 7 ) ;
      g.addEdge(1, 3, 9);
      g.addEdge(1, 4, 9 );
      g.addEdge(2, 1, 9 );
      g.addEdge(2, 4, 9);
      g.addEdge(2, 5, 4);
      g.addEdge(3, 5, 3);
      g.addEdge(4, 5, 7 );
      g.addEdge(0, 4, 10);
 
     // next exp
     g.addEdge(0, 1, 10);
     g.addEdge(0, 2, 10);
     g.addEdge(1, 3, 4 );
     g.addEdge(1, 4, 8 );
     g.addEdge(1, 2, 2 );
     g.addEdge(2, 4, 9 );
     g.addEdge(3, 5, 10 );
     g.addEdge(4, 3, 6 );
     g.addEdge(4, 5, 10 ); */
 
    cout << "Maximum flow " << g.DinicMaxflow(0, 5);
    return 0;
}
 
 

Java




// JAVA implementation of above approach
 
import java.util.*;
 
class Edge {
    public int v; // Vertex v (or "to" vertex)
                 // of a directed edge u-v. "From"
                 // vertex u can be obtained using
                 // index in adjacent array
   
    public int flow;    // flow of data in edge
   
    public int C;        // Capacity
   
    public int rev;        // To store index of reverse
                       // edge in adjacency list so that
                       // we can quickly find it.
     
    public Edge(int v, int flow, int C, int rev) {
        this.v = v;
        this.flow = flow;
        this.C = C;
        this.rev = rev;
    }
}
 
 
// Residual Graph
class Graph {
    private int V;                // No. of vertex
    private int[] level;        // Stores level of graph
    private List<Edge>[] adj;
 
    public Graph(int V) {
        adj = new ArrayList[V];
        for (int i = 0; i < V; i++) {
            adj[i] = new ArrayList<Edge>();
        }
        this.V = V;
        level = new int[V];
    }
 
      // Add edge to the graph
    public void addEdge(int u, int v, int C) {
       
          // Forward edge : 0 flow and C capacity
        Edge a = new Edge(v, 0, C, adj[v].size());
       
          // Back edge : 0 flow and 0 capacity
        Edge b = new Edge(u, 0, 0, adj[u].size());
 
        adj[u].add(a);
        adj[v].add(b);
    }
 
      // Finds if more flow can be sent from s to t.
    // Also assigns levels to nodes.
    public boolean BFS(int s, int t) {
        for (int i = 0; i < V; i++) {
            level[i] = -1;
        }
 
        level[s] = 0;        // Level of source vertex
 
           // Create a queue, enqueue source vertex
        // and mark source vertex as visited here
        // level[] array works as visited array also.
        LinkedList<Integer> q = new LinkedList<Integer>();
        q.add(s);
 
        ListIterator<Edge> i;
        while (q.size() != 0) {
            int u = q.poll();
 
            for (i = adj[u].listIterator(); i.hasNext();) {
                Edge e = i.next();
                if (level[e.v] < 0 && e.flow < e.C) {
                   
                      // Level of current vertex is -
                      // Level of parent + 1
                    level[e.v] = level[u] + 1;
                    q.add(e.v);
                }
            }
        }
 
        return level[t] < 0 ? false : true;
    }
 
    // A DFS based function to send flow after BFS has
    // figured out that there is a possible flow and
    // constructed levels. This function called multiple
    // times for a single call of BFS.
    // flow : Current flow send by parent function call
    // start[] : To keep track of next edge to be explored.
    //           start[i] stores  count of edges explored
    //           from i.
    //  u : Current vertex
    //  t : Sink
    public int sendFlow(int u, int flow, int t, int start[]) {
       
          // Sink reached
        if (u == t) {
            return flow;
        }
 
          // Traverse all adjacent edges one -by - one.
        for (; start[u] < adj[u].size(); start[u]++) {
           
              // Pick next edge from adjacency list of u
            Edge e = adj[u].get(start[u]);
 
            if (level[e.v] == level[u] + 1 && e.flow < e.C) {
                  // find minimum flow from u to t
                int curr_flow = Math.min(flow, e.C - e.flow);
 
                int temp_flow = sendFlow(e.v, curr_flow, t, start);
                 
                  // flow is greater than zero
                if (temp_flow > 0) {
                      // add flow  to current edge
                    e.flow += temp_flow;
                   
                      // subtract flow from reverse edge
                    // of current edge
                    adj[e.v].get(e.rev).flow -= temp_flow;
                    return temp_flow;
                }
            }
        }
 
        return 0;
    }
 
      // Returns maximum flow in graph
    public int DinicMaxflow(int s, int t) {
        if (s == t) {
            return -1;
        }
 
        int total = 0;
 
          // Augment the flow while there is path
        // from source to sink
        while (BFS(s, t) == true) {
           
              // store how many edges are visited
            // from V { 0 to V }
            int[] start = new int[V + 1];
 
              // while flow is not zero in graph from S to D
            while (true) {
                int flow = sendFlow(s, Integer.MAX_VALUE, t, start);
                if (flow == 0) {
                    break;
                }
               
                  // Add path flow to overall flow
                total += flow;
            }
        }
 
          // Return maximum flow
        return total;
    }
}
 
// Driver Code
public class Main {
    public static void main(String args[]) {
        Graph g = new Graph(6);
        g.addEdge(0, 1, 16);
        g.addEdge(0, 2, 13);
        g.addEdge(1, 2, 10);
        g.addEdge(1, 3, 12);
        g.addEdge(2, 1, 4);
        g.addEdge(2, 4, 14);
        g.addEdge(3, 2, 9);
        g.addEdge(3, 5, 20);
        g.addEdge(4, 3, 7);
        g.addEdge(4, 5, 4);
       
        // next exmp
      /*g.addEdge(0, 1, 3 );
        g.addEdge(0, 2, 7 ) ;
        g.addEdge(1, 3, 9);
        g.addEdge(1, 4, 9 );
        g.addEdge(2, 1, 9 );
        g.addEdge(2, 4, 9);
        g.addEdge(2, 5, 4);
        g.addEdge(3, 5, 3);
        g.addEdge(4, 5, 7 );
        g.addEdge(0, 4, 10);
 
       // next exp
       g.addEdge(0, 1, 10);
       g.addEdge(0, 2, 10);
       g.addEdge(1, 3, 4 );
       g.addEdge(1, 4, 8 );
       g.addEdge(1, 2, 2 );
       g.addEdge(2, 4, 9 );
       g.addEdge(3, 5, 10 );
       g.addEdge(4, 3, 6 );
       g.addEdge(4, 5, 10 ); */
                   
        System.out.println("Maximum flow " + g.DinicMaxflow(0, 5));
      }
}
 
// This code is contributed by Amit Mangal
 
 

Python3




# Python implementation of Dinic's Algorithm
class Edge:
    def __init__(self, v, flow, C, rev):
        self.v = v
        self.flow = flow
        self.C = C
        self.rev = rev
 
# Residual Graph
 
 
class Graph:
    def __init__(self, V):
        self.adj = [[] for i in range(V)]
        self.V = V
        self.level = [0 for i in range(V)]
 
    # add edge to the graph
    def addEdge(self, u, v, C):
 
        # Forward edge : 0 flow and C capacity
        a = Edge(v, 0, C, len(self.adj[v]))
 
        # Back edge : 0 flow and 0 capacity
        b = Edge(u, 0, 0, len(self.adj[u]))
        self.adj[u].append(a)
        self.adj[v].append(b)
 
    # Finds if more flow can be sent from s to t
    # Also assigns levels to nodes
    def BFS(self, s, t):
        for i in range(self.V):
            self.level[i] = -1
 
        # Level of source vertex
        self.level[s] = 0
 
        # Create a queue, enqueue source vertex
        # and mark source vertex as visited here
        # level[] array works as visited array also
        q = []
        q.append(s)
        while q:
            u = q.pop(0)
            for i in range(len(self.adj[u])):
                e = self.adj[u][i]
                if self.level[e.v] < 0 and e.flow < e.C:
 
                    # Level of current vertex is
                    # level of parent + 1
                    self.level[e.v] = self.level[u]+1
                    q.append(e.v)
 
        # If we can not reach to the sink we
        # return False else True
        return False if self.level[t] < 0 else True
 
# A DFS based function to send flow after BFS has
# figured out that there is a possible flow and
# constructed levels. This functions called multiple
# times for a single call of BFS.
# flow : Current flow send by parent function call
# start[] : To keep track of next edge to be explored
#           start[i] stores count of edges explored
#           from i
# u : Current vertex
# t : Sink
    def sendFlow(self, u, flow, t, start):
        # Sink reached
        if u == t:
            return flow
 
        # Traverse all adjacent edges one -by -one
        while start[u] < len(self.adj[u]):
 
            # Pick next edge from adjacency list of u
            e = self.adj[u][start[u]]
            if self.level[e.v] == self.level[u]+1 and e.flow < e.C:
 
                # find minimum flow from u to t
                curr_flow = min(flow, e.C-e.flow)
                temp_flow = self.sendFlow(e.v, curr_flow, t, start)
 
                # flow is greater than zero
                if temp_flow and temp_flow > 0:
 
                    # add flow to current edge
                    e.flow += temp_flow
 
                    # subtract flow from reverse edge
                    # of current edge
                    self.adj[e.v][e.rev].flow -= temp_flow
                    return temp_flow
            start[u] += 1
 
    # Returns maximum flow in graph
    def DinicMaxflow(self, s, t):
 
        # Corner case
        if s == t:
            return -1
 
        # Initialize result
        total = 0
 
        # Augument the flow while there is path
        # from source to sink
        while self.BFS(s, t) == True:
 
            # store how many edges are visited
            # from V { 0 to V }
            start = [0 for i in range(self.V+1)]
            while True:
                flow = self.sendFlow(s, float('inf'), t, start)
                if not flow:
                    break
 
                # Add path flow to overall flow
                total += flow
 
        # return maximum flow
        return total
 
 
g = Graph(6)
g.addEdge(0, 1, 16)
g.addEdge(0, 2, 13)
g.addEdge(1, 2, 10)
g.addEdge(1, 3, 12)
g.addEdge(2, 1, 4)
g.addEdge(2, 4, 14)
g.addEdge(3, 2, 9)
g.addEdge(3, 5, 20)
g.addEdge(4, 3, 7)
g.addEdge(4, 5, 4)
print("Maximum flow", g.DinicMaxflow(0, 5))
 
# This code is contributed by rupasriachanta421.
 
 

C#




using System;
using System.Collections.Generic;
 
class Edge {
    public int v;  // Vertex v (or "to" vertex)
                 // of a directed edge u-v. "From"
                 // vertex u can be obtained using
                 // index in adjacent array
   
    public int flow;  // flow of data in edge
     
    public int C;  // capacity
     
    public int rev; // To store index of reverse
             // edge in adjacency list so that
             // we can quickly find it.
              
    public Edge(int v, int flow, int C, int rev) {
        this.v = v;
        this.flow = flow;
        this.C = C;
        this.rev = rev;
    }
}
 
// Residual Graph
class Graph {
    private int V;       // No. of vertex        
    private int[] level;       // Stores level of graph
    private List<Edge>[] adj;
 
    public Graph(int V) {
        adj = new List<Edge>[V];
        for (int i = 0; i < V; i++) {
            adj[i] = new List<Edge>();
        }
        this.V = V;
        level = new int[V];
    }
 
    // Add edge to the graph
    public void addEdge(int u, int v, int C) {
         
        // Forward edge : 0 flow and C capacity
        Edge a = new Edge(v, 0, C, adj[v].Count);
         
        // Back edge : 0 flow and 0 capacity
        Edge b = new Edge(u, 0, 0, adj[u].Count);
        adj[u].Add(a);
        adj[v].Add(b);
    }
     
    // Finds if more flow can be sent from s to t.
    // Also assigns levels to nodes.
    public bool BFS(int s, int t) {
        for (int j = 0; j < V; j++) {
            level[j] = -1;
        }
 
        level[s] = 0;   // Level of source vertex
 
           // Create a queue, enqueue source vertex
        // and mark source vertex as visited here
        // level[] array works as visited array also.
        Queue<int> q = new Queue<int>();
        q.Enqueue(s);
 
        List<Edge>.Enumerator i;
        while (q.Count != 0) {
            int u = q.Dequeue();
 
            for (i = adj[u].GetEnumerator(); i.MoveNext();) {
                Edge e = i.Current;
                if (level[e.v] < 0 && e.flow < e.C) {
                    // Level of current vertex is -
                      // Level of parent + 1
                       
                    level[e.v] = level[u] + 1;
                    q.Enqueue(e.v);
                }
            }
        }
 
        return level[t] < 0 ? false : true;
    }
     
    // A DFS based function to send flow after BFS has
    // figured out that there is a possible flow and
    // constructed levels. This function called multiple
    // times for a single call of BFS.
    // flow : Current flow send by parent function call
    // start[] : To keep track of next edge to be explored.
    //           start[i] stores  count of edges explored
    //           from i.
    //  u : Current vertex
    //  t : Sink
    public int sendFlow(int u, int flow, int t, int[] start) {
         
        // Sink reached
        if (u == t) {
            return flow;
        }
         
        // Traverse all adjacent edges one -by - one.
        for (; start[u] < adj[u].Count; start[u]++) {
             
            // Pick next edge from adjacency list of u
            Edge e = adj[u][start[u]];
 
            if (level[e.v] == level[u] + 1 && e.flow < e.C) {
                // find minimum flow from u to t
                int curr_flow = Math.Min(flow, e.C - e.flow);
                int temp_flow = sendFlow(e.v, curr_flow, t, start);
                 
                // flow is greater than zero
                if (temp_flow > 0) {
                    // add flow  to current edge
                    e.flow += temp_flow;
                     
                    // subtract flow from reverse edge
                    // of current edge
                    adj[e.v][e.rev].flow -= temp_flow;
                    return temp_flow;
                }
            }
        }
 
        return 0;
    }
     
    // Returns maximum flow in graph
    public int DinicMaxflow(int s, int t) {
        if (s == t) {
            return -1;
        }
 
        int total = 0;
         
        // Augment the flow while there is path
        // from source to sink
        while (BFS(s, t) == true) {
             
            // store how many edges are visited
            // from V { 0 to V }
            int[] start = new int[V + 1];
 
            // while flow is not zero in graph from S to D
            while (true) {
                int flow = sendFlow(s, int.MaxValue, t, start);
                if (flow == 0) {
                    break;
                }
                 
                // Add path flow to overall flow
                total += flow;
            }
        }
         
        // Return maximum flow
        return total;
    }
}
 
// Driver Code
public class Gfg {
    public static void Main() {
        Graph g = new Graph(6);
        g.addEdge(0, 1, 16);
        g.addEdge(0, 2, 13);
        g.addEdge(1, 2, 10);
        g.addEdge(1, 3, 12);
        g.addEdge(2, 1, 4);
        g.addEdge(2, 4, 14);
        g.addEdge(3, 2, 9);
        g.addEdge(3, 5, 20);
        g.addEdge(4, 3, 7);
        g.addEdge(4, 5, 4);
         
        // next exmp
      /*g.addEdge(0, 1, 3 );
        g.addEdge(0, 2, 7 ) ;
        g.addEdge(1, 3, 9);
        g.addEdge(1, 4, 9 );
        g.addEdge(2, 1, 9 );
        g.addEdge(2, 4, 9);
        g.addEdge(2, 5, 4);
        g.addEdge(3, 5, 3);
        g.addEdge(4, 5, 7 );
        g.addEdge(0, 4, 10);
 
       // next exp
       g.addEdge(0, 1, 10);
       g.addEdge(0, 2, 10);
       g.addEdge(1, 3, 4 );
       g.addEdge(1, 4, 8 );
       g.addEdge(1, 2, 2 );
       g.addEdge(2, 4, 9 );
       g.addEdge(3, 5, 10 );
       g.addEdge(4, 3, 6 );
       g.addEdge(4, 5, 10 ); */
         
       
        Console.Write("Maximum flow " + g.DinicMaxflow(0, 5));
    }
}
 
 

Javascript




// Javascript implementation of Dinic's Algorithm
 
      // A class to represent a edge between
      // two vertex
      class Edge {
        constructor(v, flow, C, rev) {
          // Vertex v (or "to" vertex)
          // of a directed edge u-v. "From"
          // vertex u can be obtained using
          // index in adjacent array.
          this.v = v;
          // flow of data in edge
          this.flow = flow;
          // capacity
          this.C = C;
          // To store index of reverse
          // edge in adjacency list so that
          // we can quickly find it.
          this.rev = rev;
        }
      }
 
      // Residual Graph
      class Graph {
        constructor(V) {
          this.V = V; // number of vertex
          this.adj = Array.from(Array(V), () => new Array());
          this.level = new Array(V); // stores level of a node
        }
 
        // add edge to the graph
        addEdge(u, v, C) {
          // Forward edge : 0 flow and C capacity
          let a = new Edge(v, 0, C, this.adj[v].length);
 
          // Back edge : 0 flow and 0 capacity
          let b = new Edge(u, 0, 0, this.adj[u].length);
 
          this.adj[u].push(a);
          this.adj[v].push(b); // reverse edge
        }
 
        // Finds if more flow can be sent from s to t.
        // Also assigns levels to nodes.
        BFS(s, t) {
          for (let i = 0; i < this.V; i++) this.level[i] = -1;
 
          this.level[s] = 0; // Level of source vertex
 
          // Create a queue, enqueue source vertex
          // and mark source vertex as visited here
          // level[] array works as visited array also.
          let q = new Array();
          q.push(s);
 
          while (q.length != 0) {
            let u = q[0];
            q.shift();
            for (let j in this.adj[u]) {
              let e = this.adj[u][j];
              if (this.level[e.v] < 0 && e.flow < e.C) {
                // Level of current vertex is,
                // level of parent + 1
                this.level[e.v] = this.level[u] + 1;
 
                q.push(e.v);
              }
            }
          }
 
          // IF we can not reach to the sink we
          // return false else true
          return this.level[t] < 0 ? false : true;
        }
 
        // A DFS based function to send flow after BFS has
        // figured out that there is a possible flow and
        // constructed levels. This function called multiple
        // times for a single call of BFS.
        // flow : Current flow send by parent function call
        // start[] : To keep track of next edge to be explored.
        //           start[i] stores  count of edges explored
        //           from i.
        //  u : Current vertex
        //  t : Sink
        sendFlow(u, flow, t, start) {
          // Sink reached
          if (u == t) return flow;
 
          // Traverse all adjacent edges one -by - one.
          while (start[u] < this.adj[u].length) {
            // Pick next edge from adjacency list of u
            let e = this.adj[u][start[u]];
 
            if (this.level[e.v] == this.level[u] + 1 && e.flow < e.C) {
              // find minimum flow from u to t
              let curr_flow = Math.min(flow, e.C - e.flow);
 
              let temp_flow = this.sendFlow(e.v, curr_flow, t, start);
 
              // flow is greater than zero
              if (temp_flow > 0) {
                // add flow  to current edge
                e.flow += temp_flow;
 
                // subtract flow from reverse edge
                // of current edge
                this.adj[e.v][e.rev].flow -= temp_flow;
                return temp_flow;
              }
            }
            start[u] = start[u] + 1;
          }
 
          return 0;
        }
 
        // Returns maximum flow in graph
        DinicMaxflow(s, t) {
          // Corner case
          if (s == t) return -1;
 
          let total = 0; // Initialize result
 
          // Augment the flow while there is path
          // from source to sink
          while (this.BFS(s, t) == true) {
            // store how many edges are visited
            // from V { 0 to V }
            let start = new Array(this.V + 1);
            start.fill(0);
 
            // while flow is not zero in graph from S to D
            while (true) {
              let flow = this.sendFlow(s, Number.MAX_VALUE, t, start);
              if (!flow) {
                break;
              }
              // Add path flow to overall flow
              total += flow;
            }
          }
 
          // return maximum flow
          return total;
        }
      }
 
      // Driver Code
 
      let g = new Graph(6);
      g.addEdge(0, 1, 16);
      g.addEdge(0, 2, 13);
      g.addEdge(1, 2, 10);
      g.addEdge(1, 3, 12);
      g.addEdge(2, 1, 4);
      g.addEdge(2, 4, 14);
      g.addEdge(3, 2, 9);
      g.addEdge(3, 5, 20);
      g.addEdge(4, 3, 7);
      g.addEdge(4, 5, 4);
 
      // next exmp
      /*g.addEdge(0, 1, 3 );
              g.addEdge(0, 2, 7 ) ;
              g.addEdge(1, 3, 9);
              g.addEdge(1, 4, 9 );
              g.addEdge(2, 1, 9 );
              g.addEdge(2, 4, 9);
              g.addEdge(2, 5, 4);
              g.addEdge(3, 5, 3);
              g.addEdge(4, 5, 7 );
              g.addEdge(0, 4, 10);
 
             // next exp
             g.addEdge(0, 1, 10);
             g.addEdge(0, 2, 10);
             g.addEdge(1, 3, 4 );
             g.addEdge(1, 4, 8 );
             g.addEdge(1, 2, 2 );
             g.addEdge(2, 4, 9 );
             g.addEdge(3, 5, 10 );
             g.addEdge(4, 3, 6 );
             g.addEdge(4, 5, 10 ); */
 
      console.log("Maximum flow " + g.DinicMaxflow(0, 5));
 
 
Output
Maximum flow 23

Time Complexity : O(EV2). 

  • Doing a BFS to construct level graph takes O(E) time. 
  • Sending multiple more flows until a blocking flow is reached takes O(VE) time. 
  • The outer loop runs at-most O(V) time. 
  • In each iteration, we construct new level graph and find blocking flow. It can be proved that the number of levels increase at least by one in every iteration (Refer the below reference video for the proof). So the outer loop runs at most O(V) times.
  • Therefore overall time complexity is O(EV2). 

Space complexity:
The space complexity of Dinic’s algorithm is O(V+E), since it requires O(V) to store the level array and O(E) to store the graph’s adjacency list.

 



Next Article
Max Area of Island - Largest in Boolean Matrix

N

Nishant Singh
Improve
Article Tags :
  • DSA
  • Graph
  • BFS
  • DFS
  • Max-Flow
Practice Tags :
  • BFS
  • DFS
  • Graph

Similar Reads

  • Graph Algorithms
    Graph algorithms are methods used to manipulate and analyze graphs, solving various range of problems like finding the shortest path, cycles detection. If you are looking for difficulty-wise list of problems, please refer to Graph Data Structure. BasicsGraph and its representationsBFS and DFS Breadt
    3 min read
  • Introduction to Graph Data Structure
    Graph Data Structure is a non-linear data structure consisting of vertices and edges. It is useful in fields such as social network analysis, recommendation systems, and computer networks. In the field of sports data science, graph data structure can be used to analyze and understand the dynamics of
    15+ min read
  • Graph and its representations
    A Graph is a non-linear data structure consisting of vertices and edges. The vertices are sometimes also referred to as nodes and the edges are lines or arcs that connect any two nodes in the graph. More formally a Graph is composed of a set of vertices( V ) and a set of edges( E ). The graph is den
    12 min read
  • Types of Graphs with Examples
    A graph is a mathematical structure that represents relationships between objects by connecting a set of points. It is used to establish a pairwise relationship between elements in a given set. graphs are widely used in discrete mathematics, computer science, and network theory to represent relation
    9 min read
  • Basic Properties of a Graph
    A Graph is a non-linear data structure consisting of nodes and edges. The nodes are sometimes also referred to as vertices and the edges are lines or arcs that connect any two nodes in the graph. The basic properties of a graph include: Vertices (nodes): The points where edges meet in a graph are kn
    4 min read
  • Applications, Advantages and Disadvantages of Graph
    Graph is a non-linear data structure that contains nodes (vertices) and edges. A graph is a collection of set of vertices and edges (formed by connecting two vertices). A graph is defined as G = {V, E} where V is the set of vertices and E is the set of edges. Graphs can be used to model a wide varie
    7 min read
  • Transpose graph
    Transpose of a directed graph G is another directed graph on the same set of vertices with all of the edges reversed compared to the orientation of the corresponding edges in G. That is, if G contains an edge (u, v) then the converse/transpose/reverse of G contains an edge (v, u) and vice versa. Giv
    9 min read
  • Difference Between Graph and Tree
    Graphs and trees are two fundamental data structures used in computer science to represent relationships between objects. While they share some similarities, they also have distinct differences that make them suitable for different applications. What is Graph?A graph data structure is a collection o
    2 min read
  • BFS and DFS on Graph

    • Breadth First Search or BFS for a Graph
      Given a undirected graph represented by an adjacency list adj, where each adj[i] represents the list of vertices connected to vertex i. Perform a Breadth First Search (BFS) traversal starting from vertex 0, visiting vertices from left to right according to the adjacency list, and return a list conta
      15+ min read

    • Depth First Search or DFS for a Graph
      In Depth First Search (or DFS) for a graph, we traverse all adjacent vertices one by one. When we traverse an adjacent vertex, we completely finish the traversal of all vertices reachable through that adjacent vertex. This is similar to a tree, where we first completely traverse the left subtree and
      13 min read

    • Applications, Advantages and Disadvantages of Depth First Search (DFS)
      Depth First Search is a widely used algorithm for traversing a graph. Here we have discussed some applications, advantages, and disadvantages of the algorithm. Applications of Depth First Search:1. Detecting cycle in a graph: A graph has a cycle if and only if we see a back edge during DFS. So we ca
      4 min read

    • Applications, Advantages and Disadvantages of Breadth First Search (BFS)
      We have earlier discussed Breadth First Traversal Algorithm for Graphs. Here in this article, we will see the applications, advantages, and disadvantages of the Breadth First Search. Applications of Breadth First Search: 1. Shortest Path and Minimum Spanning Tree for unweighted graph: In an unweight
      4 min read

    • Iterative Depth First Traversal of Graph
      Given a directed Graph, the task is to perform Depth First Search of the given graph. Note: Start DFS from node 0, and traverse the nodes in the same order as adjacency list. Note : There can be multiple DFS traversals of a graph according to the order in which we pick adjacent vertices. Here we pic
      10 min read

    • BFS for Disconnected Graph
      In the previous post, BFS only with a particular vertex is performed i.e. it is assumed that all vertices are reachable from the starting vertex. But in the case of a disconnected graph or any vertex that is unreachable from all vertex, the previous implementation will not give the desired output, s
      14 min read

    • Transitive Closure of a Graph using DFS
      Given a directed graph, find out if a vertex v is reachable from another vertex u for all vertex pairs (u, v) in the given graph. Here reachable means that there is a path from vertex u to v. The reach-ability matrix is called transitive closure of a graph. For example, consider below graph: Transit
      8 min read

    • Difference between BFS and DFS
      Breadth-First Search (BFS) and Depth-First Search (DFS) are two fundamental algorithms used for traversing or searching graphs and trees. This article covers the basic difference between Breadth-First Search and Depth-First Search. ParametersBFSDFSStands forBFS stands for Breadth First Search.DFS st
      2 min read

    Cycle in a Graph

    • Detect Cycle in a Directed Graph
      Given the number of vertices V and a list of directed edges, determine whether the graph contains a cycle or not. Examples: Input: V = 4, edges[][] = [[0, 1], [0, 2], [1, 2], [2, 0], [2, 3]] Output: trueExplanation: The diagram clearly shows a cycle 0 → 2 → 0 Input: V = 4, edges[][] = [[0, 1], [0, 2
      15+ min read

    • Detect cycle in an undirected graph
      Given an undirected graph, the task is to check if there is a cycle in the given graph. Examples: Input: V = 4, edges[][]= [[0, 1], [0, 2], [1, 2], [2, 3]] Output: trueExplanation: The diagram clearly shows a cycle 0 → 2 → 1 → 0 Input: V = 4, edges[][] = [[0, 1], [1, 2], [2, 3]] Output: falseExplana
      8 min read

    • Detect Cycle in a directed graph using colors
      Given a directed graph represented by the number of vertices V and a list of directed edges, determine whether the graph contains a cycle. Your task is to implement a function that accepts V (number of vertices) and edges (an array of directed edges where each edge is a pair [u, v]), and returns tru
      9 min read

    • Detect a negative cycle in a Graph | (Bellman Ford)
      Given a directed weighted graph, the task is to find whether the given graph contains any negative-weight cycle or not. Note: A negative-weight cycle is a cycle in a graph whose edges sum to a negative value. Example: Input: Output: No Input: Output: Yes Algorithm to Find Negative Cycle in a Directe
      15+ min read

    • Cycles of length n in an undirected and connected graph
      Given an undirected and connected graph and a number n, count the total number of simple cycles of length n in the graph. A simple cycle of length n is defined as a cycle that contains exactly n vertices and n edges. Note that for an undirected graph, each cycle should only be counted once, regardle
      10 min read

    • Detecting negative cycle using Floyd Warshall
      We are given a directed graph. We need compute whether the graph has negative cycle or not. A negative cycle is one in which the overall sum of the cycle comes negative. Negative weights are found in various applications of graphs. For example, instead of paying cost for a path, we may get some adva
      12 min read

    • Clone a Directed Acyclic Graph
      A directed acyclic graph (DAG) is a graph which doesn't contain a cycle and has directed edges. We are given a DAG, we need to clone it, i.e., create another graph that has copy of its vertices and edges connecting them. Examples: Input : 0 - - - > 1 - - - -> 4 | / \ ^ | / \ | | / \ | | / \ |
      12 min read

geeksforgeeks-footer-logo
Corporate & Communications Address:
A-143, 7th Floor, Sovereign Corporate Tower, Sector- 136, Noida, Uttar Pradesh (201305)
Registered Address:
K 061, Tower K, Gulshan Vivante Apartment, Sector 137, Noida, Gautam Buddh Nagar, Uttar Pradesh, 201305
GFG App on Play Store GFG App on App Store
Advertise with us
  • Company
  • About Us
  • Legal
  • Privacy Policy
  • In Media
  • Contact Us
  • Advertise with us
  • GFG Corporate Solution
  • Placement Training Program
  • Languages
  • Python
  • Java
  • C++
  • PHP
  • GoLang
  • SQL
  • R Language
  • Android Tutorial
  • Tutorials Archive
  • DSA
  • Data Structures
  • Algorithms
  • DSA for Beginners
  • Basic DSA Problems
  • DSA Roadmap
  • Top 100 DSA Interview Problems
  • DSA Roadmap by Sandeep Jain
  • All Cheat Sheets
  • Data Science & ML
  • Data Science With Python
  • Data Science For Beginner
  • Machine Learning
  • ML Maths
  • Data Visualisation
  • Pandas
  • NumPy
  • NLP
  • Deep Learning
  • Web Technologies
  • HTML
  • CSS
  • JavaScript
  • TypeScript
  • ReactJS
  • NextJS
  • Bootstrap
  • Web Design
  • Python Tutorial
  • Python Programming Examples
  • Python Projects
  • Python Tkinter
  • Python Web Scraping
  • OpenCV Tutorial
  • Python Interview Question
  • Django
  • Computer Science
  • Operating Systems
  • Computer Network
  • Database Management System
  • Software Engineering
  • Digital Logic Design
  • Engineering Maths
  • Software Development
  • Software Testing
  • DevOps
  • Git
  • Linux
  • AWS
  • Docker
  • Kubernetes
  • Azure
  • GCP
  • DevOps Roadmap
  • System Design
  • High Level Design
  • Low Level Design
  • UML Diagrams
  • Interview Guide
  • Design Patterns
  • OOAD
  • System Design Bootcamp
  • Interview Questions
  • Inteview Preparation
  • Competitive Programming
  • Top DS or Algo for CP
  • Company-Wise Recruitment Process
  • Company-Wise Preparation
  • Aptitude Preparation
  • Puzzles
  • School Subjects
  • Mathematics
  • Physics
  • Chemistry
  • Biology
  • Social Science
  • English Grammar
  • Commerce
  • World GK
  • GeeksforGeeks Videos
  • DSA
  • Python
  • Java
  • C++
  • Web Development
  • Data Science
  • CS Subjects
@GeeksforGeeks, Sanchhaya Education Private Limited, All rights reserved
We use cookies to ensure you have the best browsing experience on our website. By using our site, you acknowledge that you have read and understood our Cookie Policy & Privacy Policy
Lightbox
Improvement
Suggest Changes
Help us improve. Share your suggestions to enhance the article. Contribute your expertise and make a difference in the GeeksforGeeks portal.
geeksforgeeks-suggest-icon
Create Improvement
Enhance the article with your expertise. Contribute to the GeeksforGeeks community and help create better learning resources for all.
geeksforgeeks-improvement-icon
Suggest Changes
min 4 words, max Words Limit:1000

Thank You!

Your suggestions are valuable to us.

What kind of Experience do you want to share?

Interview Experiences
Admission Experiences
Career Journeys
Work Experiences
Campus Experiences
Competitive Exam Experiences