diff --git a/Graph/max_flow.cpp b/Graph/max_flow.cpp new file mode 100644 index 0000000..e4756df --- /dev/null +++ b/Graph/max_flow.cpp @@ -0,0 +1,80 @@ +/* Maximum-Flow solver using Dinic's Blocking Flow Algorithm. + * Time Complexity: + * - O(V^2 E) for general graphs, but in practice ~O(E^1.5) + * - O(V^(1/2) E) for bipartite matching + * - O(min(V^(2/3), E^(1/2)) E) for unit capacity graphs + */ + +template +class max_flow { + static const T INF = numeric_limits::max(); + struct edge { + int t, rev; + T cap, f; + }; + vector adj[V]; + int dist[V]; + int ptr[V]; + bool bfs(int s, int t) { + memset(dist, -1, sizeof dist); + dist[s] = 0; + queue q({ s }); + while (!q.empty() && dist[t] == -1) { + int n = q.front(); + q.pop(); + for (auto& e : adj[n]) { + if (dist[e.t] == -1 && e.cap != e.f) { + dist[e.t] = dist[n] + 1; + q.push(e.t); + } + } + } + return dist[t] != -1; + } + T augment(int n, T amt, int t) { + if (n == t) return amt; + for (; ptr[n] < adj[n].size(); ptr[n]++) { + edge& e = adj[n][ptr[n]]; + if (dist[e.t] == dist[n] + 1 && e.cap != e.f) { + T flow = augment(e.t, min(amt, e.cap - e.f), t); + if (flow != 0) { + e.f += flow; + adj[e.t][e.rev].f -= flow; + return flow; + } + } + } + return 0; + } +public: + void add(int u, int v, T cap = 1, T rcap=0) { + adj[u].push_back({ v, (int) adj[v].size(), cap, 0 }); + adj[v].push_back({ u, (int) adj[u].size() - 1, rcap, 0 }); + } + T calc(int s, int t) { + T flow = 0; + while (bfs(s, t)) { + memset(ptr, 0, sizeof ptr); + while (T df = augment(s, INF, t)) flow += df; + } + return flow; + } + void clear() { + for (int n = 0; n < V; n++) adj[n].clear(); + } +}; + +int main() { + /* Example of usage */ + max_flow<4> network; + network.add(0, 1, 75); + network.add(0, 2, 50); + network.add(1, 2, 40); + network.add(1, 3, 50); + network.add(2, 3, 30); + + int flow = network.calc(0, 3); + + /* Max-flow should be 80. */ + cout << flow << endl; +} \ No newline at end of file