C++ Library for Competitive Programming
#include "emthrm/graph/flow/maximum_flow/ford-fulkerson.hpp"
ある始点からある終点までのフローの最大値である。
最大フロー最小カット定理より最小カットと一致する。
アルゴリズム | 時間計算量 |
---|---|
Ford–Fulkerson 法 | 最大流を $F$ とおくと $O(F \lvert E \rvert)$ |
Dinic 法 | 最大流を $F$ とおくと $O\left(\min \left\lbrace {\lvert V \rvert}^2 \lvert E \rvert,\ F \lvert E \rvert,\ {\lvert E \rvert}^{3/2} \max_{e \in E} C_e,\ \sqrt{\lvert V \rvert} \lvert E \rvert \max_{v \in V} \min \left\lbrace \sum_{e \in \delta^-(v) \subset E} C_e, \sum_{e \in \delta^+(v) \subset E} C_e \right\rbrace \right\rbrace\right)$ |
template <typename T>
struct FordFulkerson;
T
:容量を表す型名前 | 説明 |
---|---|
std::vector<std::vector<Edge>> graph |
残余グラフ |
名前 | 効果・戻り値 | 備考 |
---|---|---|
explicit FordFulkerson(const int n); |
頂点数 $N$ のオブジェクトを構築する。 | |
void add_edge(const int src, const int dst, const T cap); |
容量 $\mathrm{cap}$ の辺 $(\mathrm{src}, \mathrm{dst})$ を追加する。 | |
T maximum_flow(const int s, const int t, T limit = std::numeric_limits<T>::max()); |
上限を $\mathrm{limit}$ とした始点 $s$ から終点 $t$ までの最大流 | 容量が整数でなければ、停止しないときがある。 |
名前 | 説明 |
---|---|
Edge |
辺を表す構造体 |
struct Edge;
名前 | 説明 |
---|---|
int dst |
終点 |
int rev |
頂点 $\mathrm{dst}$ における逆辺のインデックス |
T cap |
残りの容量 |
名前 | 効果 |
---|---|
explicit Edge(const int dst, const T cap, const int rev); |
コンストラクタ |
template <typename T>
struct Dinic;
T
:容量を表す型名前 | 説明 |
---|---|
std::vector<std::vector<Edge>> graph |
残余グラフ |
名前 | 効果・戻り値 |
---|---|
explicit Dinic(const int n); |
頂点数 $N$ のオブジェクトを構築する。 |
void add_edge(const int src, const int dst, const T cap); |
容量 $\mathrm{cap}$ の辺 $(\mathrm{src}, \mathrm{dst})$ を追加する。 |
T maximum_flow(const int s, const int t, T limit = std::numeric_limits<T>::max()); |
上限を $\mathrm{limit}$ とした始点 $s$ から終点 $t$ までの最大流 |
名前 | 説明 |
---|---|
Edge |
辺を表す構造体 |
struct Edge;
名前 | 説明 |
---|---|
int dst |
終点 |
int rev |
頂点 $\mathrm{dst}$ における逆辺のインデックス |
T cap |
残りの容量 |
名前 | 効果 |
---|---|
explicit Edge(const int dst, const T cap, const int rev); |
コンストラクタ |
複数の source や sink が存在する。
新たな始点や終点を用意する。その始点から各 source に流出量と等しい容量をもつ辺を、各 sink からその終点に流入量と等しい容量をもつ辺を追加すればよい。
無向グラフ
両方向に同容量の有向辺を追加すればよい。または逆辺に等しい容量をもたせればよい?
頂点にも容量が存在する。
頂点を入頂点と出頂点に分割する。入ってくる辺を入頂点、出ていく辺を出頂点につなぎ直し、入頂点から出頂点に頂点の容量と同容量の辺を追加すればよい。
辺の容量を増やす。
残余グラフに対して、容量を増やした後に再び最大流を求め、元の答えに加えればよい。
辺 $e = (u, v)$ の容量を $c$ だけ減らす。
$e.\mathrm{cap} \geq c$ のとき
$e.\mathrm{cap} \gets e.\mathrm{cap} - c$ とすればよい。
$e.\mathrm{cap} < c$ のとき
$c \gets c - e.\mathrm{cap},\ e.\mathrm{cap} \gets 0$ とする。残余グラフにおける $u$ から $v$ までの最大流を $c^{\prime}$ とおく。
$c^{\prime} \geq c$ のとき
$u$ から $v$ まで $c$ だけ流せばよい。
$c^{\prime} < c$ のとき
$u$ から $v$ まで $c^{\prime}$ だけ流す。終点から $v$ まで、そして $u$ から始点まで $c - c^{\prime}$ 押し戻す必要があり、最大流は $c - c^{\prime}$ 減る。
Ford–Fulkerson 法
Dinic 法
#ifndef EMTHRM_GRAPH_FLOW_MAXIMUM_FLOW_FORD_FULKERSON_HPP_
#define EMTHRM_GRAPH_FLOW_MAXIMUM_FLOW_FORD_FULKERSON_HPP_
#include <algorithm>
#include <limits>
#include <vector>
namespace emthrm {
template <typename T>
struct FordFulkerson {
struct Edge {
int dst, rev;
T cap;
explicit Edge(const int dst, const T cap, const int rev)
: dst(dst), rev(rev), cap(cap) {}
};
std::vector<std::vector<Edge>> graph;
explicit FordFulkerson(const int n)
: graph(n), timestamp(0), is_used(n, -1) {}
void add_edge(const int src, const int dst, const T cap) {
graph[src].emplace_back(dst, cap, graph[dst].size());
graph[dst].emplace_back(src, 0, graph[src].size() - 1);
}
T maximum_flow(const int s, const int t,
T limit = std::numeric_limits<T>::max()) {
T res = 0;
while (limit > 0) {
const T tmp = dfs(s, t, limit);
++timestamp;
if (tmp == 0) break;
limit -= tmp;
res += tmp;
}
return res;
}
private:
int timestamp;
std::vector<int> is_used;
T dfs(const int ver, const int t, const T flow) {
if (ver == t) return flow;
is_used[ver] = timestamp;
for (Edge& e : graph[ver]) {
if (is_used[e.dst] < timestamp && e.cap > 0) {
const T tmp = dfs(e.dst, t, std::min(flow, e.cap));
if (tmp > 0) {
e.cap -= tmp;
graph[e.dst][e.rev].cap += tmp;
return tmp;
}
}
}
return 0;
}
};
} // namespace emthrm
#endif // EMTHRM_GRAPH_FLOW_MAXIMUM_FLOW_FORD_FULKERSON_HPP_
#line 1 "include/emthrm/graph/flow/maximum_flow/ford-fulkerson.hpp"
#include <algorithm>
#include <limits>
#include <vector>
namespace emthrm {
template <typename T>
struct FordFulkerson {
struct Edge {
int dst, rev;
T cap;
explicit Edge(const int dst, const T cap, const int rev)
: dst(dst), rev(rev), cap(cap) {}
};
std::vector<std::vector<Edge>> graph;
explicit FordFulkerson(const int n)
: graph(n), timestamp(0), is_used(n, -1) {}
void add_edge(const int src, const int dst, const T cap) {
graph[src].emplace_back(dst, cap, graph[dst].size());
graph[dst].emplace_back(src, 0, graph[src].size() - 1);
}
T maximum_flow(const int s, const int t,
T limit = std::numeric_limits<T>::max()) {
T res = 0;
while (limit > 0) {
const T tmp = dfs(s, t, limit);
++timestamp;
if (tmp == 0) break;
limit -= tmp;
res += tmp;
}
return res;
}
private:
int timestamp;
std::vector<int> is_used;
T dfs(const int ver, const int t, const T flow) {
if (ver == t) return flow;
is_used[ver] = timestamp;
for (Edge& e : graph[ver]) {
if (is_used[e.dst] < timestamp && e.cap > 0) {
const T tmp = dfs(e.dst, t, std::min(flow, e.cap));
if (tmp > 0) {
e.cap -= tmp;
graph[e.dst][e.rev].cap += tmp;
return tmp;
}
}
}
return 0;
}
};
} // namespace emthrm