SwadhyAI Notes

All DSA notes

DSA Graphs

Maximum Flow

The CDN must push as many Gbps as possible from origin s to edge PoP t. Pipes have capacities. Question-led: when is a routing plan optimal? When its equals a .

Algorithms search the for an (or push preflow). Residual reverse edges are how you undo a bad earlier push without restarting.

Algorithm journey

1

Capacities + conservation

Valid flow contract first.

2

Forward leftover + reverse undo.

3

Augment or push

Raise value; update residuals.

4

No s→t residual path ⇒ optimal.

What actually happens

Naive idea: pick disjoint paths greedily and sum bottlenecks. Breaks when the optimum needs to partially cancel flow on an edge (residual reverse) to free a better combination.

Better idea: maintain a feasible flow and residual graph. Augment along residual s–t paths until none remain. Then residual reachability from s defines a min cut of equal capacity.

The improved design still fails with bad path choice on irrational capacities (non-termination), with modeling bugs (missing reverse edges), or if you confuse cut capacity with residual capacity.

Invariant

Every intermediate state is a feasible flow. Flow value never exceeds any s–t cut capacity. When no residual s–t path exists, value equals the residual source-side cut capacity (max-flow min-cut).

How to choose a max-flow method

1. Teaching / small graphs? Ford-Fulkerson intuition; Edmonds-Karp for a polynomial guarantee.

2. Sparse competitive graphs? Dinic is a strong default.

3. Dense / practical large nets? Push-relabel variants often win.

Quantitative check

Edmonds-Karp is O(VE²). At V=200, E=1000 that is ~4×10⁷ edge scans in the bound: usually fine. At V=5×10³, E=2×10⁴, prefer Dinic or push-relabel.

Interactive residual-network lab

Residual-network invariant lab

Step through augmentation, then read the minimum cut directly from residual reachability.

Flow value: 0 / 15
0/100/50/150/100/10sabt

Stage 1 of 4

Zero flow

Every forward residual capacity equals its capacity; every paired reverse edge starts at 0.

EdgeForwardReverse
s → a100
s → b50
a → b150
a → t100
b → t100
current path saturated

The contract a valid flow must satisfy

Capacity

For every directed edge, 0 ≤ f(u,v) ≤ c(u,v). Capacities must be non-negative.

Skew symmetry

f(u,v) = −f(v,u) in the paired-edge model. A reverse edge records the right to cancel earlier flow.

Conservation

Every vertex except s and t has equal inflow and outflow. The source's net outflow is the flow value.

Modeling detail: the definition does not require the source to have no incoming edges or the sink to have no outgoing edges. Algorithms work as long as source and sink are distinct and the value is measured as net flow.

🔑 Key Concepts

Source (s)

The distinguished starting vertex. Flow value is its net outflow; incoming edges are allowed by the formal model.

Sink (t)

The distinguished destination vertex. Its net inflow equals the flow value; outgoing edges need not be forbidden.

Capacity c(u, v)

The maximum amount of flow that can pass through an edge from u to v. Flow cannot exceed capacity.

Flow f(u, v)

The actual amount of flow passing through edge (u, v). Must satisfy: 0 ≤ f(u, v) ≤ c(u, v).

🎯 Key Insight: Flow Conservation

For every node except the source and sink, the total flow coming IN must equal the total flow going OUT. This is called flow conservation - like water flowing through a pipe junction: what comes in must go out!

∑ f(u, v) = ∑ f(v, w) for all v ≠ s, t

🔄 Residual Graph

The residual graph shows the remaining capacity in the network after some flow has been sent. It's crucial for finding augmenting paths.

Forward Edge

Residual capacity = c(u, v) - f(u, v)

How much more flow can be pushed

Backward Edge

Residual capacity = f(u, v)

How much flow can be "undone"

Implement both directions as a paired object: if edge i points to v, store the index of its reverse edge in adj[v]. An augmentation of Δ subtracts Δ from the forward residual capacity and adds it to the paired reverse. This representation keeps parallel and antiparallel input edges distinct.

A safe residual-edge primitive in both languages

Python

python
class Edge:
    def __init__(self, to: int, rev: int, residual: int) -> None:
        self.to = to
        self.rev = rev
        self.residual = residual

class ResidualNetwork:
    def __init__(self, n: int) -> None:
        if n < 0:
            raise ValueError("vertex count must be non-negative")
        self.adj = [[] for _ in range(n)]

    def add_edge(self, u: int, v: int, capacity: int) -> None:
        if not (0 <= u < len(self.adj) and 0 <= v < len(self.adj)):
            raise IndexError("vertex out of range")
        if u == v:
            raise ValueError("self-loops are not supported")
        if capacity < 0:
            raise ValueError("capacity must be non-negative")
        forward = Edge(v, len(self.adj[v]), capacity)
        reverse = Edge(u, len(self.adj[u]), 0)
        self.adj[u].append(forward)
        self.adj[v].append(reverse)

    def push(self, u: int, edge_index: int, amount: int) -> None:
        edge = self.adj[u][edge_index]
        if amount < 0 or amount > edge.residual:
            raise ValueError("invalid augmentation")
        edge.residual -= amount
        self.adj[edge.to][edge.rev].residual += amount

network = ResidualNetwork(2)
network.add_edge(0, 1, 7)
network.push(0, 0, 3)
assert network.adj[0][0].residual == 4
assert network.adj[1][0].residual == 3

Java

java
import java.util.ArrayList;
import java.util.List;

public class ResidualNetwork {
    static final class Edge {
        final int to;
        final int rev;
        long residual;

        Edge(int to, int rev, long residual) {
            this.to = to;
            this.rev = rev;
            this.residual = residual;
        }
    }

    private final List<List<Edge>> adj;

    ResidualNetwork(int n) {
        if (n < 0) throw new IllegalArgumentException("negative vertex count");
        adj = new ArrayList<>(n);
        for (int i = 0; i < n; i++) adj.add(new ArrayList<>());
    }

    void addEdge(int u, int v, long capacity) {
        if (u < 0 || u >= adj.size() || v < 0 || v >= adj.size()) {
            throw new IndexOutOfBoundsException("vertex out of range");
        }
        if (u == v) throw new IllegalArgumentException("self-loop");
        if (capacity < 0) throw new IllegalArgumentException("negative capacity");
        Edge forward = new Edge(v, adj.get(v).size(), capacity);
        Edge reverse = new Edge(u, adj.get(u).size(), 0L);
        adj.get(u).add(forward);
        adj.get(v).add(reverse);
    }

    void push(int u, int edgeIndex, long amount) {
        Edge edge = adj.get(u).get(edgeIndex);
        if (amount < 0 || amount > edge.residual) {
            throw new IllegalArgumentException("invalid augmentation");
        }
        edge.residual -= amount;
        adj.get(edge.to).get(edge.rev).residual += amount;
    }

    public static void main(String[] args) {
        ResidualNetwork network = new ResidualNetwork(2);
        network.addEdge(0, 1, 7L);
        network.push(0, 0, 3L);
        assert network.adj.get(0).get(0).residual == 4L;
        assert network.adj.get(1).get(0).residual == 3L;
    }
}

🔍 Did You Know? Max-Flow Min-Cut Theorem

One of the most beautiful results in graph theory: The maximum flow from source to sink equals the minimum cut capacity! A "cut" is a partition of vertices into two sets (one containing s, the other t), and its capacity is the sum of edge capacities crossing from s's side to t's side. This theorem connects two seemingly different problems!

Why max-flow equals min-cut

Weak direction: any flow crosses every s–t cut, so conservation and capacity imply |f| ≤ capacity(S,T).

Certificate at termination: after no augmenting path remains, run DFS/BFS from s over positive residual edges. Reachable vertices form S; the rest form T. Every original edge from S to T is saturated and every edge from T to S carries zero net contribution, so the inequalities become equality.

Integrality: with integer capacities, augmenting-path algorithms push integer bottlenecks, so they return an integral maximum flow. This is why matching reductions produce discrete assignments without rounding.

🛠️ Algorithms for Max Flow

AlgorithmMethodTime ComplexityBest For
Ford-FulkersonAny path finding (DFS/BFS)O(E · |f*|), integral capacitiesTeaching; small integral flow values
Edmonds-KarpBFS for shortest pathO(V E²)Small graphs; simple reference code
Dinic'sLevel graphs + blocking flowsO(V² E)Sparse graphs, matching, contest code
Push-RelabelPreflow pushingO(V² E)Large or dense graphs; tuned solvers

Modeling patterns that show up often

Bipartite matching

source → left side (1), candidate edges (1), right side → sink (1). The integral flow selects pairs.

Vertex capacities

Split v into v_in → v_out with the vertex capacity; redirect incoming and outgoing edges.

Multiple sources or sinks

Add a super-source/super-sink. Use the sum of adjacent capacities as a safe finite bound instead of a magic infinity.

Edge-disjoint paths

Give every original edge capacity 1. The maximum integral flow equals the maximum number of edge-disjoint paths.

Feasible circulation

Add demands/lower bounds, subtract lower bounds, track vertex imbalances, then connect a super-source and super-sink.

Minimum cut extraction

After max-flow, residual reachability from s labels the two sides and gives a checkable optimality certificate.

Production and edge-case checklist

  • • Reject negative capacities and invalid vertex ids.
  • • Define source == sink; robust APIs usually reject it.
  • • Keep a separate reverse-edge index; do not merge antiparallel edges accidentally. Reject or explicitly ignore self-loops.
  • • Permit parallel edges by appending, or aggregate with overflow checks.
  • • Use Python integers / Java long for capacities and total flow.
  • • Unreachable sink is valid and returns flow 0 plus the initial cut.
  • • Never mutate the caller's graph unless documented; these residual-network objects are one-shot.
  • • Verify conservation, capacity bounds, and flow == cut capacity in tests.

💼 Real World Applications

🚗 Traffic Flow Optimization

Modeling road networks to find maximum traffic flow from suburbs to city center, considering road capacities and intersections.

Example: Rush hour traffic management

✈️ Airline Scheduling

Maximizing passenger flow through airline networks, considering aircraft capacities and airport constraints.

Example: Hub-and-spoke airline networks

🖼️ Image Segmentation

Separating foreground from background in images by modeling pixels as a flow network and finding the min-cut.

Example: Photo editing "magic wand" tool

👥 Bipartite Matching

Matching jobs to workers, students to projects, or organs to patients by modeling as a max flow problem.

Example: Job assignment optimization

🌐 Network Bandwidth

Determining maximum data throughput in computer networks, considering router and link capacities.

Example: CDN optimization

⚡ Power Grid

Optimizing electricity distribution from power plants to consumers through transmission lines with capacity limits.

Example: Load balancing in power grids

💡 Pro Tip: Choosing the Right Algorithm

Use Edmonds-Karp when clarity and a simple polynomial baseline matter, Dinic's for most interview/contest sparse graphs and matching reductions, and a tuned Push-Relabel implementation for large dense instances. Benchmark on representative topology: asymptotic bounds do not predict every workload.

Short takeaway

Maximum flow equals minimum cut. Search residuals (or push preflow) until no residual s–t path remains; reverse residual edges are how you undo bad earlier routing.

Exercises

  1. Draw a network where a greedy disjoint-path packing is suboptimal, but one residual reverse augmentation recovers the true max flow.
  2. After a maximum flow, BFS in the residual graph from s. Which edges of the original network cross the min cut?
  3. Why can flow value never exceed any cut capacity? Give the one-line counting argument.

Primary sources

  • Ford & Fulkerson: Flows in Networks; max-flow min-cut.
  • Cormen et al., CLRS: Maximum flow chapter (residuals, cuts, augmenting paths).
  • Ahuja, Magnanti, Orlin: Network Flows.