Alex's Anthology of Algorithms Common Code for Contests in Concise C++
Graphs / Flows and Cuts

4.5.1 Maximum Flow (Ford-Fulkerson)

4-Graphs/4.5.1_Maximum_Flow_(Ford-Fulkerson).cpp

Given a flow network with integer capacities, find the maximum flow from a given source node to a given sink node. The flow along each edge may not exceed its capacity, and flow is conserved at every node other than the source and sink.

The Ford-Fulkerson method repeatedly finds any augmenting path from source to sink in the residual graph (here by depth-first search) and pushes as much flow as the path allows, until no augmenting path remains. This algorithm should only be used on graphs with integer capacities, because some real-valued inputs can make it fail to terminate. The Edmonds-Karp algorithm instead uses breadth-first search and always terminates in polynomial time.

  • max_flow(source, sink) modifies the global residual capacity matrix cap and returns the maximum flow. Nodes are numbered $[0, n)$, where $n$ is cap.size().

Implementation

#include <algorithm>
#include <cassert>
#include <cstdint>
#include <vector>

const int64_t INF = INT64_MAX / 4;
std::vector<std::vector<int64_t>> cap;
std::vector<char> visit;

int64_t dfs(int u, int64_t f, int sink) {
  int n = static_cast<int>(cap.size());
  if (u == sink) {
    return f;
  }
  visit[u] = true;
  for (int v = 0; v < n; v++) {
    if (!visit[v] && cap[u][v] > 0) {
      int64_t flow = dfs(v, std::min(f, cap[u][v]), sink);
      if (flow > 0) {
        cap[u][v] -= flow;
        cap[v][u] += flow;
        return flow;
      }
    }
  }
  return 0;
}

int64_t max_flow(int source, int sink) {
  assert(source != sink);
  int n = static_cast<int>(cap.size());
  int64_t total = 0;
  while (true) {
    visit.assign(n, false);
    int64_t flow = dfs(source, INF, sink);
    if (flow == 0) {
      break;
    }
    total += flow;
  }
  return total;
}

Example Usage

#include <cassert>
using namespace std;

int main() {
  // Example graph after max flow, with each edge labeled flow/capacity:
  //            2/2
  //       1 --------> 3
  //      / \          |
  // 3/4 /   \ 1/1     | 2/2
  //    /     v        v
  //   0       4 ----> 5
  //    \     ^   3/3
  // 2/3 \   / 2/2
  //      v /
  //       2
  int nodes = 6;
  cap.assign(nodes, vector<int64_t>(nodes));
  cap[0][1] = 4;
  cap[0][2] = 3;
  cap[1][3] = 2;
  cap[1][4] = 1;
  cap[2][4] = 2;
  cap[3][5] = 2;
  cap[4][5] = 3;
  assert(max_flow(0, 5) == 5);
  return 0;
}