package com.interview.graph;
import java.util.*;
/**
* Date 04/14/2014
* @author Tushar Roy
*
* Ford fulkerson method Edmonds Karp algorithm for finding max flow
*
* Capacity - Capacity of an edge to carry units from source to destination vertex
* Flow - Actual flow of units from source to destination vertex of an edge
* Residual capacity - Remaining capacity on this edge i.e capacity - flow
* AugmentedPath - Path from source to sink which has residual capacity greater than 0
*
* Time complexity is O(VE^2)
*
* References:
* http://www.geeksforgeeks.org/ford-fulkerson-algorithm-for-maximum-flow-problem/
* https://en.wikipedia.org/wiki/Edmonds%E2%80%93Karp_algorithm
*/
public class FordFulkerson {
public int maxFlow(int capacity[][], int source, int sink){
//declare and initialize residual capacity as total avaiable capacity initially.
int residualCapacity[][] = new int[capacity.length][capacity[0].length];
for (int i = 0; i < capacity.length; i++) {
for (int j = 0; j < capacity[0].length; j++) {
residualCapacity[i][j] = capacity[i][j];
}
}
//this is parent map for storing BFS parent
Map<Integer,Integer> parent = new HashMap<>();
//stores all the augmented paths
List<List<Integer>> augmentedPaths = new ArrayList<>();
//max flow we can get in this network
int maxFlow = 0;
//see if augmented path can be found from source to sink.
while(BFS(residualCapacity, parent, source, sink)){
List<Integer> augmentedPath = new ArrayList<>();
int flow = Integer.MAX_VALUE;
//find minimum residual capacity in augmented path
//also add vertices to augmented path list
int v = sink;
while(v != source){
augmentedPath.add(v);
int u = parent.get(v);
if (flow > residualCapacity[u][v]) {
flow = residualCapacity[u][v];
}
v = u;
}
augmentedPath.add(source);
Collections.reverse(augmentedPath);
augmentedPaths.add(augmentedPath);
//add min capacity to max flow
maxFlow += flow;
//decrease residual capacity by min capacity from u to v in augmented path
// and increase residual capacity by min capacity from v to u
v = sink;
while(v != source){
int u = parent.get(v);
residualCapacity[u][v] -= flow;
residualCapacity[v][u] += flow;
v = u;
}
}
printAugmentedPaths(augmentedPaths);
return maxFlow;
}
/**
* Prints all the augmented path which contribute to max flow
*/
private void printAugmentedPaths(List<List<Integer>> augmentedPaths) {
System.out.println("Augmented paths");
augmentedPaths.forEach(path -> {
path.forEach(i -> System.out.print(i + " "));
System.out.println();
});
}
/**
* Breadth first search to find augmented path
*/
private boolean BFS(int[][] residualCapacity, Map<Integer,Integer> parent,
int source, int sink){
Set<Integer> visited = new HashSet<>();
Queue<Integer> queue = new LinkedList<>();
queue.add(source);
visited.add(source);
boolean foundAugmentedPath = false;
//see if we can find augmented path from source to sink
while(!queue.isEmpty()){
int u = queue.poll();
for(int v = 0; v < residualCapacity.length; v++){
//explore the vertex only if it is not visited and its residual capacity is
//greater than 0
if(!visited.contains(v) && residualCapacity[u][v] > 0){
//add in parent map saying v got explored by u
parent.put(v, u);
//add v to visited
visited.add(v);
//add v to queue for BFS
queue.add(v);
//if sink is found then augmented path is found
if ( v == sink) {
foundAugmentedPath = true;
break;
}
}
}
}
//returns if augmented path is found from source to sink or not
return foundAugmentedPath;
}
public static void main(String args[]){
FordFulkerson ff = new FordFulkerson();
int[][] capacity = {{0, 3, 0, 3, 0, 0, 0},
{0, 0, 4, 0, 0, 0, 0},
{3, 0, 0, 1, 2, 0, 0},
{0, 0, 0, 0, 2, 6, 0},
{0, 1, 0, 0, 0, 0, 1},
{0, 0, 0, 0, 0, 0, 9},
{0, 0, 0, 0, 0, 0, 0}};
System.out.println("\nMaximum capacity " + ff.maxFlow(capacity, 0, 6));
}
}