$\newcommand{\O}{\mathrm{O}}$
グラフ上の $s$ -> $t$ 間最大流を高速に求めるアルゴリズム. Dinitz と綴られることも多い.
動的木を用いることで高速化が可能になる(参考).
(関数)
add_edge$(from, to, cap)$ : 容量 $cap$ の辺 $(from, to)$ を追加する
solve$(s, t)$ : $s, t$ 間の最大フローを計算する
時間計算量: $\O (n^2 m)$ 容量スケーリング版は $\O (nm \log U)$ (ただし $U$ は辺容量の最大値)
template<typename T> class Dinic { private: int V; vector<int> level,iter; void bfs(int s) { fill(level.begin(),level.end(),-1); queue<int> que; level[s] = 0; que.push(s); while(!que.empty()){ int v = que.front(); que.pop(); for(auto& e : G[v]){ if(e.cap > 0 && level[e.to] < 0){ level[e.to] = level[v] + 1; que.push(e.to); } } } } T dfs(int v,int t,T f) { if(v==t){ return f; } for(int& i = iter[v]; i < (int)G[v].size(); i++){ edge& e = G[v][i]; if(e.cap > 0 && level[v] < level[e.to]){ T d = dfs(e.to,t,min(f,e.cap)); if(d > 0){ e.cap -= d; G[e.to][e.rev].cap += d; return d; } } } return 0; } public: struct edge{ int to, rev; T cap; }; vector<vector<edge> > G; Dinic(const int node_size) : V(node_size), level(V), iter(V), G(V){} //辺を張る void add_edge(int from,int to,T cap) { G[from].push_back((edge){to, (int)G[to].size(), cap}); G[to].push_back((edge){from, (int)G[from].size()-1, (T)0}); } //最大流を計算 T solve(int s,int t) { T flow = 0; for(;;){ bfs(s); if(level[t] < 0) return flow; fill(iter.begin(),iter.end(),0); T f; while((f=dfs(s,t,numeric_limits<T>::max())) > 0){ flow += f; } } } };
template<typename T> class Dinic { public: static_assert(std::is_integral<T>::value, "Integral required."); struct edge{ int to; T cap; int rev; }; private: const int V; T max_cap; vector<int> level, iter, que; static unsigned long long floor2(unsigned long long v){ v = v | (v >> 1), v = v | (v >> 2); v = v | (v >> 4), v = v | (v >> 8); v = v | (v >> 16), v = v | (v >> 32); return v - (v >> 1); } void bfs(const int s, const T base) { fill(level.begin(), level.end(), -1); level[s] = 0; int qh = 0, qt = 0; for(que[qt++] = s; qh < qt;){ int v = que[qh++]; for(edge& e : G[v]){ if(level[e.to] < 0 && e.cap >= base){ level[e.to] = level[v] + 1; que[qt++] = e.to; } } } } T dfs(const int v, const int t, const T base, const T f) { if(v == t) return f; T sum = 0; for(int& i = iter[v]; i < (int)G[v].size(); i++){ edge& e = G[v][i]; if(e.cap >= base && level[v] < level[e.to]){ T d = dfs(e.to, t, base, min(f - sum, e.cap)); if(d > 0){ e.cap -= d; G[e.to][e.rev].cap += d; sum += d; if(f - sum < base) break; } } } return sum; } public: vector<vector<edge> > G; Dinic(const int node_size) : V(node_size), max_cap(0), level(V), iter(V), que(V), G(V){} //辺を張る void add_edge(const int from, const int to, const T cap) { G[from].push_back((edge){to, cap, (int)G[to].size()}); G[to].push_back((edge){from, (T)0, (int)G[from].size()-1}); max_cap = max(max_cap, cap); } //最大流を計算(max_cap は辺の容量の上限) T solve(const int s, const int t){ T flow = 0; for(T base = floor2(max_cap); base >= 1;){ bfs(s, base); if(level[t] < 0){ base >>= 1; continue; } fill(iter.begin(), iter.end(), 0); flow += dfs(s, t, base, numeric_limits<T>::max()); } return flow; } };
AOJ : Maximum Flow 提出コード 提出コード(容量スケーリング版)