kopricky アルゴリズムライブラリ

Dinic Algorithm

コードについての説明(個人的メモ)

グラフ上の s -> t 間最大流を高速に求めるアルゴリズム. Dinitz と綴られることも多い.
動的木を用いることで高速化が可能になる(参考).

(関数)
add_edge(from,to,cap) : 容量 cap の辺 (from,to) を追加する
solve(s,t) : s,t 間の最大フローを計算する

時間計算量: O(n2m) 容量スケーリング版は O(nmlogU) (ただし U は辺容量の最大値)

コード

  1. template<typename T> class Dinic {
  2. private:
  3. int V;
  4. vector<int> level,iter;
  5. void bfs(int s) {
  6. fill(level.begin(),level.end(),-1);
  7. queue<int> que;
  8. level[s] = 0;
  9. que.push(s);
  10. while(!que.empty()){
  11. int v = que.front();
  12. que.pop();
  13. for(auto& e : G[v]){
  14. if(e.cap > 0 && level[e.to] < 0){
  15. level[e.to] = level[v] + 1;
  16. que.push(e.to);
  17. }
  18. }
  19. }
  20. }
  21. T dfs(int v,int t,T f) {
  22. if(v==t){
  23. return f;
  24. }
  25. for(int& i = iter[v]; i < (int)G[v].size(); i++){
  26. edge& e = G[v][i];
  27. if(e.cap > 0 && level[v] < level[e.to]){
  28. T d = dfs(e.to,t,min(f,e.cap));
  29. if(d > 0){
  30. e.cap -= d;
  31. G[e.to][e.rev].cap += d;
  32. return d;
  33. }
  34. }
  35. }
  36. return 0;
  37. }
  38.  
  39. public:
  40. struct edge{
  41. int to, rev;
  42. T cap;
  43. };
  44. vector<vector<edge> > G;
  45.  
  46. Dinic(const int node_size) : V(node_size), level(V), iter(V), G(V){}
  47. //辺を張る
  48. void add_edge(int from,int to,T cap) {
  49. G[from].push_back((edge){to, (int)G[to].size(), cap});
  50. G[to].push_back((edge){from, (int)G[from].size()-1, (T)0});
  51. }
  52. //最大流を計算
  53. T solve(int s,int t) {
  54. T flow = 0;
  55. for(;;){
  56. bfs(s);
  57. if(level[t] < 0) return flow;
  58. fill(iter.begin(),iter.end(),0);
  59. T f;
  60. while((f=dfs(s,t,numeric_limits<T>::max())) > 0){
  61. flow += f;
  62. }
  63. }
  64. }
  65. };

コード(容量スケーリング版)

  1. template<typename T> class Dinic {
  2. public:
  3. static_assert(std::is_integral<T>::value, "Integral required.");
  4. struct edge{
  5. int to;
  6. T cap;
  7. int rev;
  8. };
  9. private:
  10. const int V;
  11. T max_cap;
  12. vector<int> level, iter, que;
  13. static unsigned long long floor2(unsigned long long v){
  14. v = v | (v >> 1), v = v | (v >> 2);
  15. v = v | (v >> 4), v = v | (v >> 8);
  16. v = v | (v >> 16), v = v | (v >> 32);
  17. return v - (v >> 1);
  18. }
  19. void bfs(const int s, const T base) {
  20. fill(level.begin(), level.end(), -1);
  21. level[s] = 0;
  22. int qh = 0, qt = 0;
  23. for(que[qt++] = s; qh < qt;){
  24. int v = que[qh++];
  25. for(edge& e : G[v]){
  26. if(level[e.to] < 0 && e.cap >= base){
  27. level[e.to] = level[v] + 1;
  28. que[qt++] = e.to;
  29. }
  30. }
  31. }
  32. }
  33. T dfs(const int v, const int t, const T base, const T f) {
  34. if(v == t) return f;
  35. T sum = 0;
  36. for(int& i = iter[v]; i < (int)G[v].size(); i++){
  37. edge& e = G[v][i];
  38. if(e.cap >= base && level[v] < level[e.to]){
  39. T d = dfs(e.to, t, base, min(f - sum, e.cap));
  40. if(d > 0){
  41. e.cap -= d;
  42. G[e.to][e.rev].cap += d;
  43. sum += d;
  44. if(f - sum < base) break;
  45. }
  46. }
  47. }
  48. return sum;
  49. }
  50.  
  51. public:
  52. vector<vector<edge> > G;
  53.  
  54. Dinic(const int node_size) : V(node_size), max_cap(0), level(V), iter(V), que(V), G(V){}
  55. //辺を張る
  56. void add_edge(const int from, const int to, const T cap) {
  57. G[from].push_back((edge){to, cap, (int)G[to].size()});
  58. G[to].push_back((edge){from, (T)0, (int)G[from].size()-1});
  59. max_cap = max(max_cap, cap);
  60. }
  61. //最大流を計算(max_cap は辺の容量の上限)
  62. T solve(const int s, const int t){
  63. T flow = 0;
  64. for(T base = floor2(max_cap); base >= 1;){
  65. bfs(s, base);
  66. if(level[t] < 0){
  67. base >>= 1;
  68. continue;
  69. }
  70. fill(iter.begin(), iter.end(), 0);
  71. flow += dfs(s, t, base, numeric_limits<T>::max());
  72. }
  73. return flow;
  74. }
  75. };

verify 用の問題

AOJ : Maximum Flow 提出コード 提出コード(容量スケーリング版)