#include<bits/stdc++.h> #define ll long long // Dinic to find max-flow/min-cut // Usage: // Dinic dinic; // dinic.init(n); // dinic.addEdge(...); // maxFlow = dinic.run(source, sink); struct Dinic { int n; vector< vector<ll> > capa; vector< vector<ll> > flow; vector< vector<int> > adj; vector<int> dlevel; vector<int> prev; vector<int> visit; int maxCapacity; Dinic(){ maxCapacity = 1e9; } void init(int n_) { n = n_; capa.resize(n+1); flow.resize(n+1); adj.resize(n+1); dlevel.resize(n+1); prev.resize(n+1, 0); visit.resize(n+1); for (int i = 0; i <= n; ++i) { capa[i].resize(n+1); flow[i].resize(n+1); fill(capa[i].begin(), capa[i].begin()+n+1, 0); fill(flow[i].begin(), flow[i].begin()+n+1, 0); adj[i].clear(); } fill(dlevel.begin(), dlevel.begin()+n+1, 0); fill(prev.begin(), prev.begin()+n+1, 0); fill(visit.begin(), visit.begin()+n+1, 0); } void addEdge(int u, int v, int w) { capa[u][v] += w; capa[v][u] += w; flow[v][u] += w; } void prepareAdj() { for (int i = 0; i <= n; ++i) for (int j = 0; j <= n; ++j) if (i != j && capa[i][j] > 0) adj[i].push_back(j); } bool constructLevel(int source, int sink) { fill(dlevel.begin(), dlevel.begin()+n+1, -1); dlevel[source] = 0; queue<int> que; que.push(source); while(!que.empty()) { int vertex = que.front(); que.pop(); for (int i = 0; i < adj[vertex].size(); ++i) { int next = adj[vertex][i]; if (dlevel[next] >= 0) continue; if (capa[vertex][next] > flow[vertex][next]) { que.push(next); dlevel[next] = dlevel[vertex] + 1; } } } return dlevel[sink] >= 0; } ll makeFlow(int source, int sink) { ll ret = 0; fill(visit.begin(), visit.begin()+n+1, 0); stack<int> stk; stk.push(source); while(!stk.empty()) { int now = stk.top(); if (now != sink) { for (int i = 0; i < adj[now].size() && stk.top() == now; ++i) { int next = adj[now][i]; if (dlevel[next] != dlevel[now] + 1 || visit[next]) continue; if (capa[now][next] > flow[now][next]) { stk.push(next); prev[next] = now; } } if (stk.top() == now) { stk.pop(); visit[now] = 1; } } else { // now == sink ll f = maxCapacity, bottleneck; for (int cur = sink; cur != source; cur = abs(prev[cur])) { f = min(f, capa[prev[cur]][cur] - flow[prev[cur]][cur]); } for (int cur = sink; cur != source; cur = abs(prev[cur])) { flow[prev[cur]][cur] += f; flow[cur][prev[cur]] -= f; if (capa[prev[cur]][cur] == flow[prev[cur]][cur]) bottleneck = prev[cur]; } ret += f; while(!stk.empty() && stk.top() != bottleneck) stk.pop(); } } // cout << "ret: " << ret << endl; return ret; } ll run(int source, int sink) { prepareAdj(); ll maxFlow = 0; while (constructLevel(source, sink)) { maxFlow += makeFlow(source, sink); } return maxFlow; } };