Skip to the content.

:heavy_check_mark: Max Flow
(flow/max-flow.hpp)

最大流問題を解く.

push-relabel algorithm により $n$ 頂点 $m$ 辺のとき $O(n^2m)$ 時間.

push-relabel algorithm (概要)

preflow を更新する push,height function を更新する relabel を組み合わせたアルゴリズム.

push

以下の条件を満たす残余辺 $(u,v)$ についての操作.

Push(u, v):
  df = min(e[u], c_f[u, v])
  if (u, v) in E:
    f[u, v] += df
  else:
    f[v, u] -= df
  e[u] -= df
  e[v] += df

push 後に $c_f(u,v)=0$ となる push を saturating push と呼ぶ.

relabel

$e(u)\gt 0$ かつ $(u,\forall v)\in E_f,h(u)\leq h(v)$ なる $u$ に対する操作.

Relabel(u):
  h[u] = 1 + min(h[v] for (u, v) in E_f)

基本アルゴリズム

以下のアルゴリズムで最大フローが求められる.

GenericPushRelabel(G):
  for v in V:
    h[v] = 0
    e[v] = 0
  for (u, v) in E:
    f[u, v] = 0
  h(s) = |V|
  for v in G[s]:
    f[s, v] = c(s, v)
    e[v] = c(s, v)
    e[s] -= c(s, v)
  while (push または relabel ができる):
    (push または relabel を任意に選んで行う)
最大フローを返すこと,また停止して時間計算量が $O( V ^2 E )$ であることの証明は省略.

push/relabel の操作順

GenericPushRelabel では push/relabel を行う順序に自由度がある.

順序を適切に決めることで $O( V ^3)$ 時間や $O( V ^2\sqrt{ E })$ 時間などになる.

資料

Depends on

Verified with

Code

#pragma once

#include "data-structure/simple-queue.hpp"

template <class Cap = long long>
struct MaxFlow {
 public:
  MaxFlow() : _n(0) {}
  explicit MaxFlow(int n) : _n(n), g(n) {}

  int add_edge(int from, int to, Cap cap) {
    assert(0 <= from && from < _n);
    assert(0 <= to && to < _n);
    assert(0 <= cap);
    int m = int(pos.size());
    pos.push_back({from, int(g[from].size())});
    int from_id = int(g[from].size());
    int to_id = int(g[to].size());
    if (from == to) to_id++;
    g[from].push_back(_edge{to, to_id, cap});
    g[to].push_back(_edge{from, from_id, 0});
    return m;
  }

  struct edge {
    int from, to;
    Cap cap, flow;
  };

  edge get_edge(int i) {
    int m = int(pos.size());
    assert(0 <= i && i < m);
    auto _e = g[pos[i].first][pos[i].second];
    auto _re = g[_e.to][_e.rev];
    return edge{pos[i].first, _e.to, _e.cap + _re.cap, _re.cap};
  }
  vector<edge> edges() {
    int m = int(pos.size());
    vector<edge> result;
    for (int i = 0; i < m; i++) {
      result.push_back(get_edge(i));
    }
    return result;
  }
  void change_edge(int i, Cap new_cap, Cap new_flow) {
    int m = int(pos.size());
    assert(0 <= i && i < m);
    assert(0 <= new_flow && new_flow <= new_cap);
    auto& _e = g[pos[i].first][pos[i].second];
    auto& _re = g[_e.to][_e.rev];
    _e.cap = new_cap - new_flow;
    _re.cap = new_flow;
  }

  Cap flow(int s, int t) {
    return flow(s, t, numeric_limits<Cap>::max());
  }
  Cap flow(int s, int t, Cap flow_limit) {
    assert(0 <= s && s < _n);
    assert(0 <= t && t < _n);
    assert(s != t);

    vector<int> level(_n), iter(_n);
    SimpleQueue<int> que;

    auto bfs = [&]() {
      fill(level.begin(), level.end(), -1);
      level[s] = 0;
      que.clear();
      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) continue;
          level[e.to] = level[v] + 1;
          if (e.to == t) return;
          que.push(e.to);
        }
      }
    };
    auto dfs = [&](auto self, int v, Cap up) {
      if (v == s) return up;
      Cap res = 0;
      int level_v = level[v];
      for (int& i = iter[v]; i < int(g[v].size()); i++) {
        _edge& e = g[v][i];
        if (level_v <= level[e.to] || g[e.to][e.rev].cap == 0) continue;
        Cap d = self(self, e.to, min(up - res, g[e.to][e.rev].cap));
        if (d <= 0) continue;
        g[v][i].cap += d;
        g[e.to][e.rev].cap -= d;
        res += d;
        if (res == up) return res;
      }
      level[v] = _n;
      return res;
    };

    Cap flow = 0;
    while (flow < flow_limit) {
      bfs();
      if (level[t] == -1) break;
      fill(iter.begin(), iter.end(), 0);
      Cap f = dfs(dfs, t, flow_limit - flow);
      if (!f) break;
      flow += f;
    }
    return flow;
  }

  vector<bool> min_cut(int s) {
    vector<bool> visited(_n);
    SimpleQueue<int> que;
    que.push(s);
    while (!que.empty()) {
      int p = que.front();
      que.pop();
      visited[p] = true;
      for (auto& e : g[p]) {
        if (e.cap && !visited[e.to]) {
          visited[e.to] = true;
          que.push(e.to);
        }
      }
    }
    return visited;
  }

 private:
  int _n;
  struct _edge {
    int to, rev;
    Cap cap;
  };
  vector<pair<int, int>> pos;
  vector<vector<_edge>> g;
};

/**
 * @brief Max Flow
 * @docs docs/flow/max-flow.md
 */
#line 2 "flow/max-flow.hpp"

#line 2 "data-structure/simple-queue.hpp"

template <class T>
struct SimpleQueue {
 private:
  vector<T> a;
  int p;

 public:
  SimpleQueue() {}
  SimpleQueue(int n) { a.reserve(n); }
  void reserve(int n) { a.reserve(n); }
  int size() { return a.size() - p; }
  bool empty() { return a.size() == p; }
  void push(const T& v) { a.push_back(v); }
  T& front() { return a[p]; }
  void pop() { p++; }
  void clear() {
    a.clear();
    p = 0;
  }
};
#line 4 "flow/max-flow.hpp"

template <class Cap = long long>
struct MaxFlow {
 public:
  MaxFlow() : _n(0) {}
  explicit MaxFlow(int n) : _n(n), g(n) {}

  int add_edge(int from, int to, Cap cap) {
    assert(0 <= from && from < _n);
    assert(0 <= to && to < _n);
    assert(0 <= cap);
    int m = int(pos.size());
    pos.push_back({from, int(g[from].size())});
    int from_id = int(g[from].size());
    int to_id = int(g[to].size());
    if (from == to) to_id++;
    g[from].push_back(_edge{to, to_id, cap});
    g[to].push_back(_edge{from, from_id, 0});
    return m;
  }

  struct edge {
    int from, to;
    Cap cap, flow;
  };

  edge get_edge(int i) {
    int m = int(pos.size());
    assert(0 <= i && i < m);
    auto _e = g[pos[i].first][pos[i].second];
    auto _re = g[_e.to][_e.rev];
    return edge{pos[i].first, _e.to, _e.cap + _re.cap, _re.cap};
  }
  vector<edge> edges() {
    int m = int(pos.size());
    vector<edge> result;
    for (int i = 0; i < m; i++) {
      result.push_back(get_edge(i));
    }
    return result;
  }
  void change_edge(int i, Cap new_cap, Cap new_flow) {
    int m = int(pos.size());
    assert(0 <= i && i < m);
    assert(0 <= new_flow && new_flow <= new_cap);
    auto& _e = g[pos[i].first][pos[i].second];
    auto& _re = g[_e.to][_e.rev];
    _e.cap = new_cap - new_flow;
    _re.cap = new_flow;
  }

  Cap flow(int s, int t) {
    return flow(s, t, numeric_limits<Cap>::max());
  }
  Cap flow(int s, int t, Cap flow_limit) {
    assert(0 <= s && s < _n);
    assert(0 <= t && t < _n);
    assert(s != t);

    vector<int> level(_n), iter(_n);
    SimpleQueue<int> que;

    auto bfs = [&]() {
      fill(level.begin(), level.end(), -1);
      level[s] = 0;
      que.clear();
      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) continue;
          level[e.to] = level[v] + 1;
          if (e.to == t) return;
          que.push(e.to);
        }
      }
    };
    auto dfs = [&](auto self, int v, Cap up) {
      if (v == s) return up;
      Cap res = 0;
      int level_v = level[v];
      for (int& i = iter[v]; i < int(g[v].size()); i++) {
        _edge& e = g[v][i];
        if (level_v <= level[e.to] || g[e.to][e.rev].cap == 0) continue;
        Cap d = self(self, e.to, min(up - res, g[e.to][e.rev].cap));
        if (d <= 0) continue;
        g[v][i].cap += d;
        g[e.to][e.rev].cap -= d;
        res += d;
        if (res == up) return res;
      }
      level[v] = _n;
      return res;
    };

    Cap flow = 0;
    while (flow < flow_limit) {
      bfs();
      if (level[t] == -1) break;
      fill(iter.begin(), iter.end(), 0);
      Cap f = dfs(dfs, t, flow_limit - flow);
      if (!f) break;
      flow += f;
    }
    return flow;
  }

  vector<bool> min_cut(int s) {
    vector<bool> visited(_n);
    SimpleQueue<int> que;
    que.push(s);
    while (!que.empty()) {
      int p = que.front();
      que.pop();
      visited[p] = true;
      for (auto& e : g[p]) {
        if (e.cap && !visited[e.to]) {
          visited[e.to] = true;
          que.push(e.to);
        }
      }
    }
    return visited;
  }

 private:
  int _n;
  struct _edge {
    int to, rev;
    Cap cap;
  };
  vector<pair<int, int>> pos;
  vector<vector<_edge>> g;
};

/**
 * @brief Max Flow
 * @docs docs/flow/max-flow.md
 */
Back to top page