# FIFO Push Relabel Algorithm

• Last Updated : 22 Feb, 2023

The push–relabel algorithm (alternatively, pre flow–push algorithm) is an algorithm for computing maximum flows in a flow network. Push-relabel algorithms work in a more localized manner than the Ford Fulkerson method. Rather than examine the entire residual network to find an augmenting path, push-relabel algorithms work on one vertex at a time, looking only at the vertex’s neighbors in the residual network.

Intuition

The push relabels algorithm can be understood in terms of fluid flows. All vertex represent pipe junctions and all directed edges represent pipes having a specific capacity. Each vertex has two special properties. They contain a reservoir to store any excess flow and the vertex along with the reservoir are placed on a platform at a specific height.

We can push flow only downhill, that is, from a vertex at a greater height to one at a lower height. Initially, the source is at a height of V (number of vertices) and the sink is at a height of 0. The height of all the other vertices is 0 and increases as the algorithm progresses. First, we send as much flow as we can from the source to all of its intermediate vertices, where it is stored in their reservoir.

Now all the intermediate vertices of the source are overflowing. We can not push flow forward since they will be located at a height 0. In order to send flow forward, we must increase their height by 1.

The process continues until we reach the sink.

In the end, we empty all the excess fluid stored in any of the vertex reservoirs (if any) by sending flow back to the source. The flow obtained then will be maximum flow.

Operations

1. Push: Push operation is applied on an overflowing vertex to push the flow forward.  The algorithm finds adjacent vertices of u which are at a lower height than u. For each such adjacent vertex, it sends the maximum possible flow, which is the minimum of excess flow at u and capacity of the edge connecting u with v.
2. Relabel: Relabel operation is applied on an overflowing vertex u to increase its height. The algorithm finds adjacent vertex v of u which has the minimum height. It then updates
```*** QuickLaTeX cannot compile formula:

*** Error message:
Error: Nothing to show, formula is empty
```

Algorithm

The generic push-relabel algorithm uses an initializepre flow function. The function is presented below followed by the algorithm.

Initialize-Preflow

1. initialize height and excess flow of every vertex to 0

2. set height of source to number of vertices

3. initialize flow of each edge to 0

4. for each adjacent vertex of source, set its flow and excess flow to capacity of edge connecting them

Generic-Push-Relabel

1. Initialize-Preflow

2. while there exists an applicable push or relabel operation

3. select an applicable push or relabel operation and perform it

4. return flow

FIFO Push-Relabel vs Push-Relabel

FIFO push relabel is an optimization in the original push relabel. Instead of spending linear time finding the overflowing vertex, we organise all the overflowing vertices in a queue. Doing so allows us to find an overflowing vertex in constant time. This reduces the time complexity to O(V3) from O(V2E).

Implementation of FIFO Push-Relabel Algorithm

Example Problem Statement: In below code, a directed graph has been encapsulated in a class DirectedGraph which has been implemented first. It contains a nested class Vertex which encapsulates the edge of the graph. Consider the graph given below –

The edge from 0 -> 1 will be encapsulated by a vertex object V(1, 3) where 1 is the destination and 3 is the weight. It will be stored at index 0 of adjacency matrix. Here is the adjacency matrix of the above graph.

```0: [[1, 3], [3, 4]]
1: [[2, 1]]
2: [[3, 2]]
3: []```

## Java

 `import` `java.util.ArrayList;``import` `java.util.LinkedList;` `// DirectedGraph class explained above``class` `DirectedGraph {``    ``public` `static` `class` `Vertex {` `        ``// number of the end vertex``        ``// weight or capacity``        ``// associated with the edge` `        ``Integer i;``        ``Integer w;` `        ``public` `Vertex(Integer i, Integer w)``        ``{``            ``this``.i = i;``            ``this``.w = w;``        ``}``    ``}` `    ``final` `ArrayList > adjacencyList;``    ``int` `vertices;` `    ``public` `DirectedGraph(``int` `vertices)``    ``{``        ``this``.vertices = vertices;` `        ``adjacencyList = ``new` `ArrayList<>(vertices);``        ``for` `(``int` `i = ``0``; i < vertices; i++)``            ``adjacencyList.add(``new` `ArrayList<>());``    ``}` `    ``public` `void` `addEdge(Integer u, Integer v,``                        ``Integer weight)``    ``{``        ``adjacencyList.get(u)``            ``.add(``new` `Vertex(v, weight));``    ``}` `    ``boolean` `hasEdge(``int` `u, ``int` `v)``    ``{``        ``if` `(u >= vertices)``            ``return` `false``;` `        ``for` `(Vertex vertex : adjacencyList.get(u))``            ``if` `(vertex.i == v)``                ``return` `true``;``        ``return` `false``;``    ``}` `    ``// Returns null if no edge``    ``// is found between u and v``    ``DirectedGraph.Vertex getEdge(``int` `u, ``int` `v)``    ``{``        ``for` `(DirectedGraph.Vertex vertex :``             ``adjacencyList.get(u))``            ``if` `(vertex.i == v)``                ``return` `vertex;` `        ``return` `null``;``    ``}``}` `public` `class` `MaxFlow {``    ``private` `final` `int` `source;``    ``private` `final` `int` `sink;``    ``private` `final` `DirectedGraph graph;` `    ``private` `DirectedGraph residualGraph;` `    ``public` `MaxFlow(DirectedGraph graph,``                   ``int` `source,``                   ``int` `sink)``    ``{``        ``this``.graph = graph;``        ``this``.source = source;``        ``this``.sink = sink;``    ``}` `    ``private` `void` `initResidualGraph()``    ``{``        ``residualGraph``            ``= ``new` `DirectedGraph(graph.vertices);` `        ``// Construct residual graph``        ``for` `(``int` `u = ``0``; u < graph.vertices; u++) {` `            ``for` `(DirectedGraph.Vertex v :``                 ``graph.adjacencyList.get(u)) {` `                ``// If forward edge already``                ``// exists, update its weight``                ``if` `(residualGraph.hasEdge(u, v.i))``                    ``residualGraph.getEdge(u, v.i).w``                        ``+= v.w;` `                ``// In case it does not``                ``// exist, create one``                ``else``                    ``residualGraph.addEdge(u, v.i, v.w);` `                ``// If backward edge does``                ``// not already exist, add it``                ``if` `(!residualGraph.hasEdge(v.i, u))``                    ``residualGraph.addEdge(v.i, u, ``0``);``            ``}``        ``}``    ``}` `    ``public` `int` `FIFOPushRelabel()``    ``{``        ``initResidualGraph();` `        ``LinkedList queue``            ``= ``new` `LinkedList<>();` `        ``// Step 1: Initialize pre-flow` `        ``// to store excess flow``        ``int``[] e = ``new` `int``[graph.vertices];` `        ``// to store height of vertices``        ``int``[] h``            ``= ``new` `int``[graph.vertices];` `        ``boolean``[] inQueue``            ``= ``new` `boolean``[graph.vertices];` `        ``// set the height of source to V``        ``h = graph.vertices;` `        ``// send maximum flow possible``        ``// from source to all its adjacent vertices``        ``for` `(DirectedGraph.Vertex v :``             ``graph.adjacencyList.get(source)) {``            ``residualGraph.getEdge(source, v.i).w = ``0``;``            ``residualGraph.getEdge(v.i, source).w = v.w;` `            ``// update excess flow``            ``e[v.i] = v.w;` `            ``if` `(v.i != sink) {``                ``queue.add(v.i);``                ``inQueue[v.i] = ``true``;``            ``}``        ``}` `        ``// Step 2: Update the pre-flow``        ``// while there remains an applicable``        ``// push or relabel operation``        ``while` `(!queue.isEmpty()) {` `            ``// vertex removed from``            ``// queue in constant time``            ``int` `u = queue.removeFirst();``            ``inQueue[u] = ``false``;` `            ``relabel(u, h);``            ``push(u, e, h, queue, inQueue);``        ``}` `        ``return` `e[sink];``    ``}` `    ``private` `void` `relabel(``int` `u, ``int``[] h)``    ``{``        ``int` `minHeight = Integer.MAX_VALUE;` `        ``for` `(DirectedGraph.Vertex v :``             ``residualGraph.adjacencyList.get(u)) {``            ``if` `(v.w > ``0``)``                ``minHeight = Math.min(h[v.i],``                                     ``minHeight);``        ``}` `        ``h[u] = minHeight + ``1``;``    ``}` `    ``private` `void` `push(``int` `u, ``int``[] e, ``int``[] h,``                      ``LinkedList queue,``                      ``boolean``[] inQueue)``    ``{``        ``for` `(DirectedGraph.Vertex v :``             ``residualGraph.adjacencyList.get(u)) {``            ``// after pushing flow if``            ``// there is no excess flow,``            ``// then break``            ``if` `(e[u] == ``0``)``                ``break``;` `            ``// push more flow to``            ``// the adjacent v if possible``            ``if` `(v.w > ``0` `&& h[v.i] < h[u]) {``                ``// flow possible``                ``int` `f = Math.min(e[u], v.w);` `                ``v.w -= f;``                ``residualGraph.getEdge(v.i, u).w += f;` `                ``e[u] -= f;``                ``e[v.i] += f;` `                ``// add the new overflowing``                ``// immediate vertex to queue``                ``if` `(!inQueue[v.i] && v.i != source``                    ``&& v.i != sink) {``                    ``queue.add(v.i);``                    ``inQueue[v.i] = ``true``;``                ``}``            ``}``        ``}` `        ``// if after sending flow to all the``        ``// intermediate vertices, the``        ``// vertex is still overflowing.``        ``// add it to queue again``        ``if` `(e[u] != ``0``) {``            ``queue.add(u);``            ``inQueue[u] = ``true``;``        ``}``    ``}` `    ``public` `static` `void` `main(String[] args)``    ``{``        ``final` `int` `vertices = ``6``;``        ``final` `int` `source = ``0``;``        ``final` `int` `sink = ``5``;` `        ``DirectedGraph dg``            ``= ``new` `DirectedGraph(vertices);` `        ``dg.addEdge(``0``, ``1``, ``16``);``        ``dg.addEdge(``0``, ``2``, ``13``);``        ``dg.addEdge(``1``, ``2``, ``10``);``        ``dg.addEdge(``2``, ``1``, ``4``);``        ``dg.addEdge(``1``, ``3``, ``12``);``        ``dg.addEdge(``3``, ``2``, ``9``);``        ``dg.addEdge(``2``, ``4``, ``14``);``        ``dg.addEdge(``4``, ``5``, ``4``);``        ``dg.addEdge(``4``, ``3``, ``7``);``        ``dg.addEdge(``3``, ``5``, ``20``);` `        ``MaxFlow maxFlow``            ``= ``new` `MaxFlow(``                ``dg, source, sink);``        ``System.out.println(``            ``"Max flow: "``            ``+ maxFlow.FIFOPushRelabel());``    ``}``}`

## C#

 `using` `System;``using` `System.Collections.Generic;` `// DirectedGraph class explained above``class` `DirectedGraph``{``  ``public` `class` `Vertex``  ``{` `    ``// number of the end vertex``    ``// weight or capacity``    ``// associated with the edge` `    ``public` `int` `i;``    ``public` `int` `w;` `    ``public` `Vertex(``int` `i, ``int` `w)``    ``{``      ``this``.i = i;``      ``this``.w = w;``    ``}``  ``}` `  ``readonly` `public`  `List > adjacencyList;``  ``public` `int` `vertices;` `  ``public` `DirectedGraph(``int` `vertices)``  ``{``    ``this``.vertices = vertices;` `    ``adjacencyList = ``new` `List >(vertices);``    ``for` `(``int` `i = 0; i < vertices; i++)``      ``adjacencyList.Add(``new` `List());``  ``}` `  ``public` `void` `addEdge(``int` `u, ``int` `v,``                      ``int` `weight)``  ``{``    ``adjacencyList[u]``      ``.Add(``new` `Vertex(v, weight));``  ``}` `  ``public` `bool` `hasEdge(``int` `u, ``int` `v)``  ``{``    ``if` `(u >= vertices)``      ``return` `false``;` `    ``foreach` `(Vertex vertex ``in` `adjacencyList[u])``      ``if` `(vertex.i == v)``        ``return` `true``;``    ``return` `false``;``  ``}` `  ``// Returns null if no edge``  ``// is found between u and v``  ``public` `DirectedGraph.Vertex getEdge(``int` `u, ``int` `v)``  ``{``    ``foreach` `(DirectedGraph.Vertex vertex ``in``             ``adjacencyList[u])``      ``if` `(vertex.i == v)``        ``return` `vertex;` `    ``return` `null``;``  ``}``}` `public` `class` `MaxFlow {``  ``private` `readonly` `int` `source;``  ``private` `readonly` `int` `sink;``  ``private` `readonly` `DirectedGraph graph;` `  ``private` `DirectedGraph residualGraph;` `  ``MaxFlow(DirectedGraph graph,``          ``int` `source,``          ``int` `sink)``  ``{``    ``this``.graph = graph;``    ``this``.source = source;``    ``this``.sink = sink;``  ``}` `  ``private` `void` `initResidualGraph()``  ``{``    ``residualGraph``      ``= ``new` `DirectedGraph(graph.vertices);` `    ``// Construct residual graph``    ``for` `(``int` `u = 0; u < graph.vertices; u++) {` `      ``foreach` `(DirectedGraph.Vertex v ``in``               ``graph.adjacencyList[u]) {` `        ``// If forward edge already``        ``// exists, update its weight``        ``if` `(residualGraph.hasEdge(u, v.i))``          ``residualGraph.getEdge(u, v.i).w``          ``+= v.w;` `        ``// In case it does not``        ``// exist, create one``        ``else``          ``residualGraph.addEdge(u, v.i, v.w);` `        ``// If backward edge does``        ``// not already exist, add it``        ``if` `(!residualGraph.hasEdge(v.i, u))``          ``residualGraph.addEdge(v.i, u, 0);``      ``}``    ``}``  ``}` `  ``public` `int` `FIFOPushRelabel()``  ``{``    ``initResidualGraph();` `    ``List<``int``> queue``      ``= ``new` `List<``int``>();` `    ``// Step 1: Initialize pre-flow` `    ``// to store excess flow``    ``int``[] e = ``new` `int``[graph.vertices];` `    ``// to store height of vertices``    ``int``[] h``      ``= ``new` `int``[graph.vertices];` `    ``bool``[] inQueue``      ``= ``new` `bool``[graph.vertices];` `    ``// set the height of source to V``    ``h = graph.vertices;` `    ``// send maximum flow possible``    ``// from source to all its adjacent vertices``    ``foreach` `(DirectedGraph.Vertex v ``in``             ``graph.adjacencyList) {``      ``residualGraph.getEdge(source, v.i).w = 0;``      ``residualGraph.getEdge(v.i, source).w = v.w;` `      ``// update excess flow``      ``e[v.i] = v.w;` `      ``if` `(v.i != sink) {``        ``queue.Add(v.i);``        ``inQueue[v.i] = ``true``;``      ``}``    ``}` `    ``// Step 2: Update the pre-flow``    ``// while there remains an applicable``    ``// push or relabel operation``    ``while` `(queue.Count!=0) {` `      ``// vertex removed from``      ``// queue in constant time``      ``int` `u = queue[0];``      ``queue.RemoveAt(0);``      ``inQueue[u] = ``false``;` `      ``relabel(u, h);``      ``push(u, e, h, queue, inQueue);``    ``}` `    ``return` `e[sink];``  ``}` `  ``private` `void` `relabel(``int` `u, ``int``[] h)``  ``{``    ``int` `minHeight = ``int``.MaxValue;` `    ``foreach` `(DirectedGraph.Vertex v ``in``             ``residualGraph.adjacencyList[u]) {``      ``if` `(v.w > 0)``        ``minHeight = Math.Min(h[v.i],``                             ``minHeight);``    ``}` `    ``h[u] = minHeight + 1;``  ``}` `  ``private` `void` `push(``int` `u, ``int``[] e, ``int``[] h,``                    ``List<``int``> queue,``                    ``bool``[] inQueue)``  ``{``    ``foreach` `(DirectedGraph.Vertex v ``in``             ``residualGraph.adjacencyList[u])``    ``{` `      ``// after pushing flow if``      ``// there is no excess flow,``      ``// then break``      ``if` `(e[u] == 0)``        ``break``;` `      ``// push more flow to``      ``// the adjacent v if possible``      ``if` `(v.w > 0 && h[v.i] < h[u]) {``        ``// flow possible``        ``int` `f = Math.Min(e[u], v.w);` `        ``v.w -= f;``        ``residualGraph.getEdge(v.i, u).w += f;` `        ``e[u] -= f;``        ``e[v.i] += f;` `        ``// add the new overflowing``        ``// immediate vertex to queue``        ``if` `(!inQueue[v.i] && v.i != source``            ``&& v.i != sink) {``          ``queue.Add(v.i);``          ``inQueue[v.i] = ``true``;``        ``}``      ``}``    ``}` `    ``// if after sending flow to all the``    ``// intermediate vertices, the``    ``// vertex is still overflowing.``    ``// add it to queue again``    ``if` `(e[u] != 0) {``      ``queue.Add(u);``      ``inQueue[u] = ``true``;``    ``}``  ``}` `  ``public` `static` `void` `Main(String[] args)``  ``{``    ``int` `vertices = 6;``    ``int` `source = 0;``    ``int` `sink = 5;` `    ``DirectedGraph dg``      ``= ``new` `DirectedGraph(vertices);` `    ``dg.addEdge(0, 1, 16);``    ``dg.addEdge(0, 2, 13);``    ``dg.addEdge(1, 2, 10);``    ``dg.addEdge(2, 1, 4);``    ``dg.addEdge(1, 3, 12);``    ``dg.addEdge(3, 2, 9);``    ``dg.addEdge(2, 4, 14);``    ``dg.addEdge(4, 5, 4);``    ``dg.addEdge(4, 3, 7);``    ``dg.addEdge(3, 5, 20);` `    ``MaxFlow maxFlow``      ``= ``new` `MaxFlow(``      ``dg, source, sink);``    ``Console.WriteLine(``      ``"Max flow: "``      ``+ maxFlow.FIFOPushRelabel());``  ``}``}` `// This code is contributed by 29AjayKumar`

## Python3

 `class` `Vertex:``    ``def` `__init__(``self``, i, w):``        ``# number of the end vertex``        ``# weight or capacity``        ``# associated with the edge``        ``self``.i ``=` `i``        ``self``.w ``=` `w` `class` `DirectedGraph:``    ``def` `__init__(``self``, vertices):``        ``self``.vertices ``=` `vertices``        ``self``.adjacencyList ``=` `[[] ``for` `i ``in` `range``(vertices)]` `    ``def` `addEdge(``self``, u, v, weight):``        ``self``.adjacencyList[u].append(Vertex(v, weight))` `    ``def` `hasEdge(``self``, u, v):``        ``if` `u >``=` `self``.vertices:``            ``return` `False` `        ``for` `vertex ``in` `self``.adjacencyList[u]:``            ``if` `vertex.i ``=``=` `v:``                ``return` `True``        ``return` `False` `    ``def` `getEdge(``self``, u, v):``        ``for` `vertex ``in` `self``.adjacencyList[u]:``            ``if` `vertex.i ``=``=` `v:``                ``return` `vertex``        ``return` `None` `class` `MaxFlow:``    ``def` `__init__(``self``, graph, source, sink):``        ``self``.graph ``=` `graph``        ``self``.source ``=` `source``        ``self``.sink ``=` `sink` `    ``def` `initResidualGraph(``self``):``        ``self``.residualGraph ``=` `DirectedGraph(``self``.graph.vertices)``        ``for` `u ``in` `range``(``self``.graph.vertices):``            ``for` `v ``in` `self``.graph.adjacencyList[u]:``                ``if` `self``.residualGraph.hasEdge(u, v.i):``                    ``self``.residualGraph.getEdge(u, v.i).w ``+``=` `v.w``                ``else``:``                    ``self``.residualGraph.addEdge(u, v.i, v.w)``                ``if` `not` `self``.residualGraph.hasEdge(v.i, u):``                    ``self``.residualGraph.addEdge(v.i, u, ``0``)` `    ``def` `FIFOPushRelabel(``self``):``        ``self``.initResidualGraph()``        ``queue ``=` `[]``        ``e ``=` `[``0``] ``*` `self``.graph.vertices``        ``h ``=` `[``0``] ``*` `self``.graph.vertices``        ``inQueue ``=` `[``False``] ``*` `self``.graph.vertices``        ``h[``self``.source] ``=` `self``.graph.vertices``        ``for` `v ``in` `self``.graph.adjacencyList[``self``.source]:``            ``self``.residualGraph.getEdge(``self``.source, v.i).w ``=` `0``            ``self``.residualGraph.getEdge(v.i, ``self``.source).w ``=` `v.w``            ``e[v.i] ``=` `v.w``            ``if` `v.i !``=` `self``.sink:``                ``queue.append(v.i)``                ``inQueue[v.i] ``=` `True``        ``# Step 2: Update the pre-flow``        ``# while there remains an applicable``        ``# push or relabel operation``        ``while` `queue:``            ``#vertex removed from``            ``# queue in constant time``            ``u ``=` `queue.pop(``0``)``            ``inQueue[u] ``=` `False``            ``self``.relabel(u, h)``            ``self``.push(u, e, h, queue, inQueue)``        ``return` `e[``self``.sink]` `    ``def` `relabel(``self``, u, h):``        ``minHeight ``=` `float``(``"inf"``)``        ``for` `v ``in` `self``.residualGraph.adjacencyList[u]:``            ``if` `v.w > ``0``:``                ``minHeight ``=` `min``(minHeight, h[v.i])``                ``h[u] ``=` `minHeight ``+` `1` `    ``def` `push(``self``, u, e, h, queue, in_queue):``        ``for` `v ``in` `self``.residualGraph.adjacencyList[u]:``            ``# after pushing flow if``            ``# there is no excess flow,``            ``# then break``            ``if` `e[u] ``=``=` `0``:``                ``break` `            ``# push more flow to``            ``# the adjacent v if possible``            ``if` `v.w > ``0` `and` `h[v.i] < h[u]:``                ``# flow possible``                ``f ``=` `min``(e[u], v.w)` `                ``v.w ``-``=` `f``                ``self``.residualGraph.getEdge(v.i, u).w ``+``=` `f` `                ``e[u] ``-``=` `f``                ``e[v.i] ``+``=` `f` `                ``# add the new overflowing``                ``# immediate vertex to queue``                ``if` `not` `in_queue[v.i] ``and` `v.i !``=` `self``.source ``and` `v.i !``=` `self``.sink:``                    ``queue.append(v.i)``                    ``in_queue[v.i] ``=` `True` `        ``# if after sending flow to all the``        ``# intermediate vertices, the``        ``# vertex is still overflowing.``        ``# add it to queue again``        ``if` `e[u] !``=` `0``:``            ``queue.append(u)``            ``in_queue[u] ``=` `True``vertices ``=` `6``source ``=` `0``sink ``=` `5` `dg ``=` `DirectedGraph(vertices)` `dg.addEdge(``0``, ``1``, ``16``)``dg.addEdge(``0``, ``2``, ``13``)``dg.addEdge(``1``, ``2``, ``10``)``dg.addEdge(``2``, ``1``, ``4``)``dg.addEdge(``1``, ``3``, ``12``)``dg.addEdge(``3``, ``2``, ``9``)``dg.addEdge(``2``, ``4``, ``14``)``dg.addEdge(``4``, ``5``, ``4``)``dg.addEdge(``4``, ``3``, ``7``)``dg.addEdge(``3``, ``5``, ``20``)` `maxFlow ``=` `MaxFlow(dg, source, sink)``print``(``"Max flow:"``, maxFlow.FIFOPushRelabel())`

## Javascript

 `// JavaScript code implementation:``class Vertex {` `    ``// number of the end vertex``    ``// weight or capacity``    ``// associated with the edge``    ``constructor(i, w) {``        ``this``.i = i;``        ``this``.w = w;``    ``}``}` `// DirectedGraph class explained above``class DirectedGraph {``    ``constructor(vertices) {``        ``this``.vertices = vertices;``        ``this``.adjacencyList = ``new` `Array(vertices);``        ``for` `(let i = 0; i < vertices; i++) {``            ``this``.adjacencyList[i] = ``new` `Array();``        ``}``    ``}` `    ``addEdge(u, v, weight) {``        ``this``.adjacencyList[u].push(``new` `Vertex(v, weight));``    ``}` `    ``hasEdge(u, v) {``        ``if` `(u >= ``this``.vertices) {``            ``return` `false``;``        ``}``        ``for` `(const vertex of ``this``.adjacencyList[u]) {``            ``if` `(vertex.i === v) {``                ``return` `true``;``            ``}``        ``}``        ``return` `false``;``    ``}``    ` `    ``// Returns null if no edge``    ``// is found between u and v``    ``getEdge(u, v) {``        ``for` `(const vertex of ``this``.adjacencyList[u]) {``            ``if` `(vertex.i === v) {``                ``return` `vertex;``            ``}``        ``}``        ``return` `null``;``    ``}``}` `class MaxFlow {``    ``constructor(graph, source, sink) {``        ``this``.graph = graph;``        ``this``.source = source;``        ``this``.sink = sink;``    ``}` `    ``initResidualGraph() {``        ``this``.residualGraph = ``new` `DirectedGraph(``this``.graph.vertices);``        ` `        ``// Construct residual graph``        ``for` `(let u = 0; u < ``this``.graph.vertices; u++) {``            ``for` `(const v of ``this``.graph.adjacencyList[u]) {``                ``// If forward edge already``                ``// exists, update its weight``                ``// In case it does not``                ``// exist, create one``                ``const residualCapacity = v.w - (``this``.residualGraph.getEdge(u, v.i) || { w: 0 }).w;``                ``this``.residualGraph.addEdge(u, v.i, residualCapacity);``                ``// If backward edge does``                ``// not already exist, add it``                ``this``.residualGraph.addEdge(v.i, u, 0);``            ``}``        ``}``    ``}` `    ``FIFOPushRelabel() {``        ``this``.initResidualGraph();``        ``const queue = [];``        ` `        ``// Step 1: Initialize pre-flow` `        ``// to store excess flow``        ``const e = ``new` `Array(``this``.graph.vertices).fill(0);``        ` `        ``// to store height of vertices``        ``const h = ``new` `Array(``this``.graph.vertices).fill(0);``        ``const inQueue = ``new` `Array(``this``.graph.vertices).fill(``false``);` `        ``// set the height of source to V``        ``h[``this``.source] = ``this``.graph.vertices;` `        ``// send maximum flow possible source``        ``// to all its adjacent vertices``        ``for` `(const v of ``this``.graph.adjacencyList[``this``.source]) {``            ``this``.residualGraph.getEdge(``this``.source, v.i).w = 0;``            ``this``.residualGraph.getEdge(v.i, ``this``.source).w = v.w;``            ` `            ``// update excess flow``            ``e[v.i] = v.w;` `            ``if` `(v.i !== ``this``.sink) {``                ``queue.push(v.i);``                ``inQueue[v.i] = ``true``;``            ``}``        ``}` `        ``// Step 2: Update the pre-flow``        ``// while there remains an applicable``        ``// push or relabel operation``        ``while` `(queue.length > 0) {``            ``// vertex removed from``            ``// queue in constant time``            ``const u = queue.shift();``            ``inQueue[u] = ``false``;` `            ``this``.relabel(u, h);``            ``this``.push(u, e, h, queue, inQueue);``        ``}` `        ``return` `e[``this``.sink];``    ``}` `    ``relabel(u, h) {``        ``let minHeight = Number.MAX_VALUE;``        ``for` `(const v of ``this``.residualGraph.adjacencyList[u]) {``            ``if` `(v.w > 0) {``                ``minHeight = Math.min(h[v.i], minHeight);``            ``}``        ``}``        ``h[u] = minHeight + 1;``    ``}` `    ``push(u, e, h, queue, inQueue) {``        ``for` `(const v of ``this``.residualGraph.adjacencyList[u]) {``            ``// after pushing flow if``            ``// there is no excess flow,``            ``// then break``            ``if` `(e[u] === 0) {``                ``break``;``            ``}``            ` `            ``// push more flow to``            ``// adjacent v if possible``            ``if` `(v.w > 0 && h[v.i] < h[u]) {``                ``// flow possible``                ``const f = Math.min(e[u], v.w);``            ` `                ``v.w -= f;``                ``this``.residualGraph.getEdge(v.i, u).w += f;``            ` `                ``e[u] -= f;``                ``e[v.i] += f;``            ` `                ``// add the new overflowing``                ``// immediate vertex to queue``                ``if` `(!inQueue[v.i] && v.i !== ``this``.source && v.i !== ``this``.sink) {``                    ``queue.push(v.i);``                    ``inQueue[v.i] = ``true``;``                ``}``            ``}``        ``}``        ` `        ``// if after sending flow to all the``        ``// intermediate vertices, the``        ``// vertex is still overflowing.``        ``// add it to queue again``        ``if` `(e[u] !== 0) {``            ``queue.push(u);``            ``inQueue[u] = ``true``;``        ``}``    ``}``}` `const vertices = 6;``const source = 0;``const sink = 5;` `const dg = ``new` `DirectedGraph(vertices);` `dg.addEdge(0, 1, 16);``dg.addEdge(0, 2, 13);``dg.addEdge(1, 2, 10);``dg.addEdge(2, 1, 4);``dg.addEdge(1, 3, 12);``dg.addEdge(3, 2, 9);``dg.addEdge(2, 4, 14);``dg.addEdge(4, 5, 4);``dg.addEdge(4, 3, 7);``dg.addEdge(3, 5, 20);` `const maxFlow = ``new` `MaxFlow(dg, source, sink);``conole.log(``"Max flow: "` `+ maxFlow.FIFOPushRelabel());` `// This code is contributed by sankar.`

Output

`Max flow: 23`

Time Complexity: O(V3)

My Personal Notes arrow_drop_up