Skip to main content

Ford Fulkerson Algorithm

Algorithm to find the max flow to the sink in a given [network]

https://brilliant.org/wiki/ford-fulkerson-algorithm/

https://www.youtube.com/watch?v=NwenwITjMys

O(E*mf) where E=edge, mf=value of max flow

package algorithmsinanutshell.networkflow

import kotlin.test.assertEquals


/**
* Algorithm to find the max flow to the sink in a given [network]
*
* https://brilliant.org/wiki/ford-fulkerson-algorithm/
*
* https://www.youtube.com/watch?v=NwenwITjMys
*
* O(E*mf) where E=edge, mf=value of max flow
*/
class FordFulkersonAlgorithm(private val network: Network) {

init {
network.validate()
}

private fun getPath(from: NVertex, to: NVertex, visitedEdge: MutableSet<Pair<NEdge, Int>>): Set<Pair<NEdge, Int>>? {
if (from == to) {
return visitedEdge
}
val edges = from.edges
for (edge in edges) {
val residualCapacity = edge.capacity - edge.flow

// Ignore path if residual capacity is not remaining
if (residualCapacity > 0 && !visitedEdge.contains(Pair(edge, residualCapacity))) {
// Record the current edge along with residual capacity. The minimum residual capacity is added to flow of whole path
visitedEdge.add(Pair(edge, residualCapacity))

val result = getPath(edge.end, to, visitedEdge)
if (result != null) {
// The minimum residual capacity of all edges in current path is added to flow of whole path
// Increment flow in current edge
edge.flow += visitedEdge.minOf { it.second }
return result
}
}
}
return null
}

fun calculateMaxFlow(): Int {
val source = network.source
val sink = network.sink
var path: Set<Pair<NEdge, Int>>?

// Keep looping since the path may have remaining residual capacity even after visiting it
do {
path = getPath(source, sink, mutableSetOf())
} while (path != null)

network.vertices.forEach(::println)

var totalFlow = 0
network.vertices.forEach { vertex ->
totalFlow += vertex.edges.filter {
it.end == network.sink
}.sumBy { it.flow }
}
return totalFlow
}
}

fun main() {
network1()
network2()
}

private fun network1() {
val network = Network()
val s = network.add('S')
val a = network.add('A')
val b = network.add('B')
val c = network.add('C')
val d = network.add('D')
val t = network.add('T')

network.source = s
network.sink = t

s.connect(a, 4)
s.connect(c, 3)
a.connect(b, 4)
b.connect(c, 3)
b.connect(t, 2)
c.connect(d, 6)
d.connect(t, 6)

assertEquals(7, FordFulkersonAlgorithm(network).calculateMaxFlow())
}

private fun network2() {
val network = Network()
val s = network.add('S')
val a = network.add('A')
val b = network.add('B')
val c = network.add('C')
val d = network.add('D')
val t = network.add('T')

network.source = s
network.sink = t

s.connect(a, 3)
s.connect(b, 2)

a.connect(c, 2)
a.connect(d, 2)

b.connect(c, 2)
b.connect(d, 3)

c.connect(t, 3)
d.connect(t, 2)

assertEquals(5, FordFulkersonAlgorithm(network).calculateMaxFlow())
}

Updated on 2021-07-06