tkmst201's Library

This documentation is automatically generated by online-judge-tools/verification-helper

View the Project on GitHub tkmst201/Library

:heavy_check_mark: 最大流 (Dinic)
(GraphTheory/Dinic.hpp)

概要

容量付きの有向グラフにおいて、任意の $2$ 頂点 $s, t$ に対する $s-t$ フローの最大値を求めます。
計算量は、頂点数を $N$ 、辺の数を $M$ として $\mathcal{O}(N^2M)$ です。
より高速で使い勝手の良い AC Librarymaxflow を使用したほうが良いです。


コンストラクタ

Dinic(int n)

頂点数 $n$ のグラフで初期化します。 T には容量の型を指定してください。

制約

計算量



メンバ関数

以下、頂点数を $N$ 、辺の数を $M$ とします。


int size()

グラフの頂点数 $N$ を返します。

計算量


void add_edge(int u, int v const T & cap)

頂点 $u$ から頂点 $v$ へ容量 $cap$ の有向辺を張ります。

制約

計算量

T max_flow(int s, int t)

$s-t$ フローの最大値を返します。 この関数を $2$ 回以上呼んだ場合の動作は未定義です。

制約

計算量

使用例

#include <bits/stdc++.h>
#include "GraphTheory/Dinic.hpp"
using namespace std;

int main() {
	Dinic<int> dinic(5);
	cout << "size() = " << dinic.size() << endl; // 5
	dinic.add_edge(0, 1, 2);
	dinic.add_edge(0, 2, 3);
	dinic.add_edge(1, 2, 2);
	dinic.add_edge(1, 4, 1);
	dinic.add_edge(2, 4, 3);
	cout << "max_flow(0, 4) = " << dinic.max_flow(0, 4) << endl; // 4
}


参考

2020/03/03: http://hos.ac/slides/20150319_flow.pdf
2020/03/03: http://vartkw.hatenablog.com/entry/2016/12/02/002703


Verified with

Code

#ifndef INCLUDE_GUARD_DINIC_HPP
#define INCLUDE_GUARD_DINIC_HPP

#include <vector>
#include <cassert>
#include <queue>
#include <type_traits>
#include <algorithm>
#include <limits>

/**
 * @brief https://tkmst201.github.io/Library/GraphTheory/Dinic.hpp
 */
template<typename T>
struct Dinic {
	using cap_type = T;
	
private:
	static constexpr cap_type EPS = std::is_floating_point<cap_type>() ? 1e-8 : 0;
	static constexpr cap_type INF = std::numeric_limits<cap_type>::max();
	struct Edge {
		int to, rev;
		cap_type c;
		Edge(int to, int rev, const cap_type & c) : to(to), rev(rev), c(c) {}
	};
	using Graph = std::vector<std::vector<Edge>>;
	Graph g;
	
public:
	Dinic(int n) : g(n) {}
	
	int size() const noexcept {
		return g.size();
	}
	
	void add_edge(int u, int v, const cap_type & cap) {
		assert(0 <= u && u < size());
		assert(0 <= v && v < size());
		assert(cap >= 0);
		g[u].emplace_back(v, g[v].size(), cap);
		g[v].emplace_back(u, g[u].size() - 1, 0);
	}
	
	cap_type max_flow(int s, int t) {
		assert(0 <= s && s < size());
		assert(0 <= t && t < size());
		assert(s != t);
		cap_type res = 0;
		std::vector<int> iter, level;
		while (true) {
			level.assign(size(), -1);
			std::queue<int> que;
			level[s] = 0;
			que.emplace(s);
			while (!que.empty() && level[t] == -1) {
				const int u = que.front();
				que.pop();
				for (const auto & e : g[u]) {
					if (e.c <= EPS || level[e.to] != -1) continue;
					level[e.to] = level[u] + 1;
					if (e.to == t) break;
					que.emplace(e.to);
				}
			}
			if (level[t] == -1) break;
			iter.assign(size(), 0);
			auto dfs = [&](auto self, int u, cap_type f) -> cap_type {
				if (u == t) return f;
				if (level[u] >= level[t]) return 0;
				for (int & i = iter[u]; i < static_cast<int>(g[u].size()); ++i) {
					auto & e = g[u][i];
					if (e.c <= EPS || level[u] >= level[e.to]) continue;
					const cap_type cur = self(self, e.to, std::min(f, e.c));
					if (cur > EPS) {
						e.c -= cur;
						g[e.to][e.rev].c += cur;
						return cur;
					}
				}
				return 0;
			};
			cap_type f;
			while ((f = dfs(dfs, s, INF)) > EPS) res += f;
		}
		return res;
	}
};

#endif // INCLUDE_GUARD_DINIC_HPP
#line 1 "GraphTheory/Dinic.hpp"



#include <vector>
#include <cassert>
#include <queue>
#include <type_traits>
#include <algorithm>
#include <limits>

/**
 * @brief https://tkmst201.github.io/Library/GraphTheory/Dinic.hpp
 */
template<typename T>
struct Dinic {
	using cap_type = T;
	
private:
	static constexpr cap_type EPS = std::is_floating_point<cap_type>() ? 1e-8 : 0;
	static constexpr cap_type INF = std::numeric_limits<cap_type>::max();
	struct Edge {
		int to, rev;
		cap_type c;
		Edge(int to, int rev, const cap_type & c) : to(to), rev(rev), c(c) {}
	};
	using Graph = std::vector<std::vector<Edge>>;
	Graph g;
	
public:
	Dinic(int n) : g(n) {}
	
	int size() const noexcept {
		return g.size();
	}
	
	void add_edge(int u, int v, const cap_type & cap) {
		assert(0 <= u && u < size());
		assert(0 <= v && v < size());
		assert(cap >= 0);
		g[u].emplace_back(v, g[v].size(), cap);
		g[v].emplace_back(u, g[u].size() - 1, 0);
	}
	
	cap_type max_flow(int s, int t) {
		assert(0 <= s && s < size());
		assert(0 <= t && t < size());
		assert(s != t);
		cap_type res = 0;
		std::vector<int> iter, level;
		while (true) {
			level.assign(size(), -1);
			std::queue<int> que;
			level[s] = 0;
			que.emplace(s);
			while (!que.empty() && level[t] == -1) {
				const int u = que.front();
				que.pop();
				for (const auto & e : g[u]) {
					if (e.c <= EPS || level[e.to] != -1) continue;
					level[e.to] = level[u] + 1;
					if (e.to == t) break;
					que.emplace(e.to);
				}
			}
			if (level[t] == -1) break;
			iter.assign(size(), 0);
			auto dfs = [&](auto self, int u, cap_type f) -> cap_type {
				if (u == t) return f;
				if (level[u] >= level[t]) return 0;
				for (int & i = iter[u]; i < static_cast<int>(g[u].size()); ++i) {
					auto & e = g[u][i];
					if (e.c <= EPS || level[u] >= level[e.to]) continue;
					const cap_type cur = self(self, e.to, std::min(f, e.c));
					if (cur > EPS) {
						e.c -= cur;
						g[e.to][e.rev].c += cur;
						return cur;
					}
				}
				return 0;
			};
			cap_type f;
			while ((f = dfs(dfs, s, INF)) > EPS) res += f;
		}
		return res;
	}
};
Back to top page