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:
#include <iostream> #include <vector> #include <climits> using namespace std;
// Stores the found edges vector< bool > found;
// Stores the number of nodes int N = 0;
// Stores the capacity of each edge vector<vector< int >> cap;
vector<vector< int >> flow;
// Stores the cost per unit flow of each edge vector<vector< int >> cost;
// Stores the distance from each node // and picked edges for each node vector< int > dad, dist, pi;
const int INF = INT_MAX / 2 - 1;
// Function to check if it is possible to // have a flow from the src to sink bool search( int src, int sink) {
// Initialise found[] to false
found = vector< bool >(N, false );
// Initialise the dist[] to INF
dist = vector< int >(N + 1, 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] = min(pi[k] + dist[k], INF);
// Return the value obtained at sink
return found[sink];
} // Function to obtain the maximum Flow vector< int > getMaxFlow(vector<vector< int >>& capi,
vector<vector< int >>& costi,
int src, int sink) {
cap = capi;
cost = costi;
N = cap.size();
found = vector< bool >(N, false );
flow.assign(N, vector< int >(N, 0));
dist = vector< int >(N + 1, 0);
dad = vector< int >(N, 0);
pi = vector< int >(N, 0);
int totflow = 0, totcost = 0;
// If a path exists from src to sink
while (search(src, sink)) {
// Set the default amount
int amt = INF;
int x = sink;
while (x != src) {
amt = min(
amt, flow[x][dad[x]] != 0
? flow[x][dad[x]]
: 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 Code int main() {
int s = 0, t = 4;
vector<vector< 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}};
vector<vector< 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}};
vector< int > ret = getMaxFlow(cap, cost, s, t);
cout << ret[0] << " " << ret[1] << endl;
return 0;
} // by phasing17 |
// Java Program to implement // the above approach import 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 approach from sys import maxsize
from typing import List
# Stores the found edges found = []
# Stores the number of nodes N = 0
# Stores the capacity # of each edge cap = []
flow = []
# Stores the cost per # unit flow of each edge cost = []
# Stores the distance from each node # and picked edges for each node dad = []
dist = []
pi = []
INF = maxsize / / 2 - 1
# Function to check if it is possible to # have a flow from the src to sink def 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 Flow def 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 Code if __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 |
// C# Program to implement // the above approach using System;
using System.Collections.Generic;
public class MinCostMaxFlow {
// Stores the found edges
bool [] 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 int INF
= Int32.MaxValue / 2 - 1;
// Function to check if it is possible to
// have a flow from the src to sink
bool search( int src, int sink)
{
// Initialise found[] to false
for ( int i = 0; i < found.Length; i++)
found[i] = false ;
// Initialise the dist[] to INF
for ( int i = 0; i < dist.Length; i++)
dist[i] = 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.GetLength(0);
found = new bool [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);
Console.WriteLine(ret[0] + " " + ret[1]);
}
} // This code is contributed by phasing17. |
// JS program to implement // the above approach let maxsize = Number.MAX_VALUE // Stores the found edges let found = [] // Stores the number of nodes let N = 0 // Stores the capacity // of each edge let cap = [] let flow = [] // Stores the cost per // unit flow of each edge let cost = [] // Stores the distance from each node // and picked edges for each node let dad = [] let dist = [] let pi = [] let INF = Math.floor(maxsize / 2) - 1 // Function to check if it is possible to // have a flow from the src to sink function search(src, sink)
{ // Initialise found[] to false
let found = new Array(N).fill( false )
// Initialise the dist[] to INF
let dist = new Array(N + 1).fill(INF)
// Distance from the source node
dist[src] = 0
// Iterate until src reaches N
while (src != N)
{
let best = N
found[src] = true
for ( var 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
let 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])
{
let 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 ( var 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 function getMaxFlow(capi, costi, src, sink)
{ cap = capi
cost = costi
N = (capi).length
found = new Array(N).fill( false );
flow = new Array(N);
for ( var i = 0; i < N; i++)
flow[i] = new Array(N).fill(0)
dist = new Array(N + 1).fill(INF)
dad = new Array(N).fill(0)
pi = new Array(N).fill(0)
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 = Math.min(
amt,
(flow[x][dad[x]] != 0)?flow[x][dad[x]]:
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 Code let s = 0 let 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 ] ]
let ret = getMaxFlow(cap, cost, s, t) console.log(ret[0], ret[1]) // This code is contributed by phasing17 |
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)