Minimum Cost Maximum Flow from a Graph using Bellman Ford Algorithm

23 Feb, 2022
Given a source node S, a sink node T, two matrices Cap[ ][ ] and Cost[ ][ ] representing a graph, where Cap[i][j] is the capacity of a directed edge from node i to node j and cost[i][j] is the cost of sending one unit of flow along a directed edge from node i to node j, the task is to find a flow with the minimum-cost maximum-flow possible from the given graph.
Minimum Cost Maximum Flow: Minimum cost(per unit of flow) required to deliver maximum amount of flow possible from the given graph.  
Example:
Input: S = 0, T = 4, cap[ ][ ] = {{0, 3, 4, 5, 0}, {0, 0, 2, 0, 0}, {0, 0, 0, 4, 1}, {0, 0, 0, 0, 10}, {0, 0, 0, 0, 0}}, cost[ ][ ] = {{0, 1, 0, 0, 0}, {0, 0, 0, 0, 0}, {0, 0, 0, 0, 0}, {0, 0, 0, 0, 0}, {0, 0, 0, 0, 0}} Output: 10 1 Explanation: For given graph, Max flow = 10 and Min cost = 1.
Input: S = 0, T = 4, cost[][] = { { 0, 1, 0, 0, 2 }, { 0, 0, 0, 3, 0 }, { 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 1 }, { 0, 0, 0, 0, 0 } }cap[][] = { { 0, 3, 1, 0, 3 }, { 0, 0, 2, 0, 0 }, { 0, 0, 0, 1, 6 }, { 0, 0, 0, 0, 2 }, { 0, 0, 0, 0, 0 } } Output: 6 8  
Approach:Negative cycle in the cost network is cycled with the sum of costs of all the edges in the cycle is negative. They can be detected using Bellman Ford algorithm. They should be eliminated because, practically, flow through such cycles cannot be allowed. Consider a negative cost cycle, if all flow has to pass through this cycle, the total cost is always reducing for every cycle completed. This would result in an infinite loop in the desire of minimizing the total cost. So, whenever a cost network includes a negative cycle, it implies, the cost can further be minimized (by flowing through the other side of the cycle instead of the side currently considered). A negative cycle once detected are removed by flowing a Bottleneck Capacity through all the edges in the cycle.
Now, look at what supply and demand nodes are: 
Supply nodes: These are positive Nodes that are added to the flow and which produces the flow.Demand nodes: These are negative nodes which are subtracted from the flow.Supply (or demand) at each node = Total flow leading out of the Node – The total flow leading into the Node  
The given problem is approached by sending a bottleneck capacity to all edges in the cycle to take care of the negative cycle. Additionally, since it involves demand nodes, the Bellman Ford algorithm is invoked. 
Follow the steps below to solve the problem: 
Store the capacity of an edge and the cost of that edge in two separate array.
Given the source node S and sink node T, picked edge pi, demand nodes da and distance between nodes dist, search if it’s possible to have flow from S to T.
If a flow exists, calculate the distance, value = dist + pi – pi[k] – cost[k].
Compare the distance values in dist[ ] with value and keep updating until minimum flow is obtained.
Below is the implementation of the above approach:
Java
Python3
// Java Program to implement// the above approachimport java.util.*; public class MinCostMaxFlow {     // Stores the found edges    boolean found[];     // Stores the number of nodes    int N;     // Stores the capacity    // of each edge    int cap[][];     int flow[][];     // Stores the cost per    // unit flow of each edge    int cost[][];     // Stores the distance from each node    // and picked edges for each node    int dad[], dist[], pi[];     static final int INF        = Integer.MAX_VALUE / 2 - 1;     // Function to check if it is possible to    // have a flow from the src to sink    boolean search(int src, int sink)    {         // Initialise found[] to false        Arrays.fill(found, false);         // Initialise the dist[] to INF        Arrays.fill(dist, INF);         // Distance from the source node        dist[src] = 0;         // Iterate until src reaches N        while (src != N) {             int best = N;            found[src] = true;             for (int k = 0; k < N; k++) {                 // If already found                if (found[k])                    continue;                 // Evaluate while flow                // is still in supply                if (flow[k][src] != 0) {                     // Obtain the total value                    int val                        = dist[src] + pi[src]                          - pi[k] - cost[k][src];                     // If dist[k] is > minimum value                    if (dist[k] > val) {                         // Update                        dist[k] = val;                        dad[k] = src;                    }                }                 if (flow[src][k] < cap[src][k]) {                     int val = dist[src] + pi[src]                              - pi[k] + cost[src][k];                     // If dist[k] is > minimum value                    if (dist[k] > val) {                         // Update                        dist[k] = val;                        dad[k] = src;                    }                }                 if (dist[k] < dist[best])                    best = k;            }             // Update src to best for            // next iteration            src = best;        }         for (int k = 0; k < N; k++)            pi[k]                = Math.min(pi[k] + dist[k],                           INF);         // Return the value obtained at sink        return found[sink];    }     // Function to obtain the maximum Flow    int[] getMaxFlow(int cap[][], int cost[][],                     int src, int sink)    {         this.cap = cap;        this.cost = cost;         N = cap.length;        found = new boolean[N];        flow = new int[N][N];        dist = new int[N + 1];        dad = new int[N];        pi = new int[N];         int totflow = 0, totcost = 0;         // If a path exist from src to sink        while (search(src, sink)) {             // Set the default amount            int amt = INF;            for (int x = sink; x != src; x = dad[x])                 amt = Math.min(amt,                               flow[x][dad[x]] != 0                                   ? flow[x][dad[x]]                                   : cap[dad[x]][x]                                         - flow[dad[x]][x]);             for (int x = sink; x != src; x = dad[x]) {                 if (flow[x][dad[x]] != 0) {                    flow[x][dad[x]] -= amt;                    totcost -= amt * cost[x][dad[x]];                }                else {                    flow[dad[x]][x] += amt;                    totcost += amt * cost[dad[x]][x];                }            }            totflow += amt;        }         // Return pair total cost and sink        return new int[] { totflow, totcost };    }     // Driver Code    public static void main(String args[])    {         // Creating an object flow        MinCostMaxFlow flow = new MinCostMaxFlow();         int s = 0, t = 4;         int cap[][] = { { 0, 3, 1, 0, 3 },                        { 0, 0, 2, 0, 0 },                        { 0, 0, 0, 1, 6 },                        { 0, 0, 0, 0, 2 },                        { 0, 0, 0, 0, 0 } };         int cost[][] = { { 0, 1, 0, 0, 2 },                         { 0, 0, 0, 3, 0 },                         { 0, 0, 0, 0, 0 },                         { 0, 0, 0, 0, 1 },                         { 0, 0, 0, 0, 0 } };         int ret[] = flow.getMaxFlow(cap, cost, s, t);         System.out.println(ret[0] + " " + ret[1]);    }}
# Python3 program to implement# the above approachfrom sys import maxsizefrom typing import List # Stores the found edgesfound = [] # Stores the number of nodesN = 0 # Stores the capacity# of each edgecap = [] flow = [] # Stores the cost per# unit flow of each edgecost = [] # Stores the distance from each node# and picked edges for each nodedad = []dist = []pi = [] INF = maxsize // 2 - 1 # Function to check if it is possible to# have a flow from the src to sinkdef search(src: int, sink: int) -> bool:     # Initialise found[] to false    found = [False for _ in range(N)]     # Initialise the dist[] to INF    dist = [INF for _ in range(N + 1)]     # Distance from the source node    dist[src] = 0     # Iterate until src reaches N    while (src != N):        best = N        found[src] = True         for k in range(N):             # If already found            if (found[k]):                continue             # Evaluate while flow            # is still in supply            if (flow[k][src] != 0):                 # Obtain the total value                val = (dist[src] + pi[src] -                           pi[k] - cost[k][src])                 # If dist[k] is > minimum value                if (dist[k] > val):                     # Update                    dist[k] = val                    dad[k] = src             if (flow[src][k] < cap[src][k]):                val = (dist[src] + pi[src] -                           pi[k] + cost[src][k])                 # If dist[k] is > minimum value                if (dist[k] > val):                     # Update                    dist[k] = val                    dad[k] = src             if (dist[k] < dist[best]):                best = k         # Update src to best for        # next iteration        src = best     for k in range(N):        pi[k] = min(pi[k] + dist[k], INF)     # Return the value obtained at sink    return found[sink] # Function to obtain the maximum Flowdef getMaxFlow(capi: List[List[int]],              costi: List[List[int]],              src: int, sink: int) -> List[int]:     global cap, cost, found, dist, pi, N, flow, dad    cap = capi    cost = costi     N = len(capi)    found = [False for _ in range(N)]    flow = [[0 for _ in range(N)]               for _ in range(N)]    dist = [INF for _ in range(N + 1)]    dad = [0 for _ in range(N)]    pi = [0 for _ in range(N)]     totflow = 0    totcost = 0     # If a path exist from src to sink    while (search(src, sink)):         # Set the default amount        amt = INF        x = sink                 while x != src:            amt = min(                amt, flow[x][dad[x]] if                (flow[x][dad[x]] != 0) else                  cap[dad[x]][x] - flow[dad[x]][x])            x = dad[x]         x = sink                 while x != src:            if (flow[x][dad[x]] != 0):                flow[x][dad[x]] -= amt                totcost -= amt * cost[x][dad[x]]             else:                flow[dad[x]][x] += amt                totcost += amt * cost[dad[x]][x]                             x = dad[x]         totflow += amt     # Return pair total cost and sink    return [totflow, totcost] # Driver Codeif __name__ == "__main__":     s = 0    t = 4     cap = [ [ 0, 3, 1, 0, 3 ],            [ 0, 0, 2, 0, 0 ],            [ 0, 0, 0, 1, 6 ],            [ 0, 0, 0, 0, 2 ],            [ 0, 0, 0, 0, 0 ] ]     cost = [ [ 0, 1, 0, 0, 2 ],             [ 0, 0, 0, 3, 0 ],             [ 0, 0, 0, 0, 0 ],             [ 0, 0, 0, 0, 1 ],             [ 0, 0, 0, 0, 0 ] ]     ret = getMaxFlow(cap, cost, s, t)     print("{} {}".format(ret[0], ret[1])) # This code is contributed by sanjeev2552
6 8
 
Time Complexity: O(V2 * E2) where V is the number of vertices and E is the number of edges. Auxiliary Space: O(V) 
sanjeev2552
khushboogoyal499
germanshephered48
bellman-ford
interview-preparation
Shortest Path
CS - Placements
Graph
Mathematical
Searching
Searching
Mathematical
Graph
Shortest Path
Writing code in comment?
Please use ide.geeksforgeeks.org,
generate link and share the link here.