809-max-flow-ford-fulkerson — Max Flow (Ford-Fulkerson with BFS)
Tutorial Video
Text description (accessibility)
This video demonstrates the "809-max-flow-ford-fulkerson — Max Flow (Ford-Fulkerson with BFS)" functional Rust example. Difficulty level: Fundamental. Key concepts covered: Functional Programming. Maximum flow (Ford-Fulkerson, 1956) finds the maximum amount that can flow from a source to a sink in a capacitated network. Key difference from OCaml: 1. **Residual graph**: Both languages maintain residual capacities as a 2D matrix; the backward edge increase is the key insight enabling augmentation undoing.
Tutorial
The Problem
Maximum flow (Ford-Fulkerson, 1956) finds the maximum amount that can flow from a source to a sink in a capacitated network. The Edmonds-Karp variant uses BFS (finding shortest augmenting paths) and runs in O(VE²). Applications include network traffic routing, image segmentation (min-cut = max-flow), bipartite matching (König's theorem), and supply chain optimization. It is one of the most practically important algorithms in operations research.
🎯 Learning Outcomes
cap[u][v] that decreases with forward flow and increases backwardCode Example
#![allow(clippy::all)]
//! # Max Flow (Ford-Fulkerson with BFS)
use std::collections::VecDeque;
pub fn max_flow(n: usize, edges: &[(usize, usize, i32)], source: usize, sink: usize) -> i32 {
let mut cap = vec![vec![0i32; n]; n];
for &(u, v, c) in edges {
cap[u][v] += c;
}
let mut flow = 0;
loop {
let mut parent = vec![None; n];
let mut q = VecDeque::new();
q.push_back(source);
parent[source] = Some(source);
while let Some(u) = q.pop_front() {
if u == sink {
break;
}
for v in 0..n {
if parent[v].is_none() && cap[u][v] > 0 {
parent[v] = Some(u);
q.push_back(v);
}
}
}
if parent[sink].is_none() {
break;
}
let mut path_flow = i32::MAX;
let mut v = sink;
while v != source {
let u = parent[v].unwrap();
path_flow = path_flow.min(cap[u][v]);
v = u;
}
v = sink;
while v != source {
let u = parent[v].unwrap();
cap[u][v] -= path_flow;
cap[v][u] += path_flow;
v = u;
}
flow += path_flow;
}
flow
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_flow() {
assert_eq!(
max_flow(
4,
&[(0, 1, 10), (0, 2, 10), (1, 2, 2), (1, 3, 4), (2, 3, 9)],
0,
3
),
13
);
}
}Key Differences
petgraph's flow module for Rust.s-t graph cut for image segmentation; computer vision libraries use this heavily.OCaml Approach
OCaml implements with Array.make_matrix n n 0 for capacities and Array.make n None for parent tracking. The BFS uses Queue.t. OCaml's Array.set updates capacities. The Ocamlgraph.Flow.Goldberg module implements push-relabel (faster in practice). Flow applications in OCaml appear in network simulation and bioinformatics pipelines.
Full Source
#![allow(clippy::all)]
//! # Max Flow (Ford-Fulkerson with BFS)
use std::collections::VecDeque;
pub fn max_flow(n: usize, edges: &[(usize, usize, i32)], source: usize, sink: usize) -> i32 {
let mut cap = vec![vec![0i32; n]; n];
for &(u, v, c) in edges {
cap[u][v] += c;
}
let mut flow = 0;
loop {
let mut parent = vec![None; n];
let mut q = VecDeque::new();
q.push_back(source);
parent[source] = Some(source);
while let Some(u) = q.pop_front() {
if u == sink {
break;
}
for v in 0..n {
if parent[v].is_none() && cap[u][v] > 0 {
parent[v] = Some(u);
q.push_back(v);
}
}
}
if parent[sink].is_none() {
break;
}
let mut path_flow = i32::MAX;
let mut v = sink;
while v != source {
let u = parent[v].unwrap();
path_flow = path_flow.min(cap[u][v]);
v = u;
}
v = sink;
while v != source {
let u = parent[v].unwrap();
cap[u][v] -= path_flow;
cap[v][u] += path_flow;
v = u;
}
flow += path_flow;
}
flow
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_flow() {
assert_eq!(
max_flow(
4,
&[(0, 1, 10), (0, 2, 10), (1, 2, 2), (1, 3, 4), (2, 3, 9)],
0,
3
),
13
);
}
}#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_flow() {
assert_eq!(
max_flow(
4,
&[(0, 1, 10), (0, 2, 10), (1, 2, 2), (1, 3, 4), (2, 3, 9)],
0,
3
),
13
);
}
}
Deep Comparison
OCaml vs Rust: Max Flow Ford Fulkerson
Overview
See the example.rs and example.ml files for detailed implementations.
Key Differences
| Aspect | OCaml | Rust |
|---|---|---|
| Type system | Hindley-Milner | Ownership + traits |
| Memory | GC | Zero-cost abstractions |
| Mutability | Explicit ref | mut keyword |
| Error handling | Option/Result | Result<T, E> |
See README.md for detailed comparison.