最大流
求解从源点s到汇点t的最大流量问题
Fold - fulkerson
依赖一个残留网络,每次更新一条从源点到汇点的路径的流量,在更新的时候同时在残留网络建立对应边的反边,直到残留网络没有从s - t的边,
最大流最小割定理
一个流是最大流,当且仅当他的残留网络不包含增广路径
Edmonds-Karps
对于Fold - fulkerson算法,虽然可以正确的找到他的最大流,但是他的时间复杂度依赖于边的权, 比如《算法竞赛》 P666,
对于Fold - fulkerson改进,使用bfs, 每次找到最短的增广路径,对该路径进行计算,可以大大优化时间复杂度, 一次bfs的时间复杂度是 o ( m ) , 对于bfs, 增广要处理n个点, m条边, 故时间复杂度为 o ( nm ), 综合起来时间复杂度是o ($n ^ 2 * m$)
代码 :1
- 先放一个jiangly代码 :
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
using namespace std;
constexpr int inf = 1e9;
template<class T>
struct MaxFlow {
struct _Edge {
int to;
T cap;
_Edge(int to, T cap) : to(to), cap(cap) {}
};
int n;
std::vector<_Edge> e;
std::vector<std::vector<int>> g;
std::vector<int> cur, h;
MaxFlow() {}
MaxFlow(int n) {
init(n);
}
void init(int n) {
this->n = n;
e.clear();
g.assign(n, {});
cur.resize(n);
h.resize(n);
}
bool bfs(int s, int t) {
h.assign(n, -1);
std::queue<int> que;
h[s] = 0;
que.push(s);
while (!que.empty()) {
const int u = que.front();
que.pop();
for (int i : g[u]) {
auto [v, c] = e[i];
if (c > 0 && h[v] == -1) {
h[v] = h[u] + 1;
if (v == t) {
return true;
}
que.push(v);
}
}
}
return false;
}
T dfs(int u, int t, T f) {
if (u == t) {
return f;
}
auto r = f;
for (int& i = cur[u]; i < int(g[u].size()); ++i) {
const int j = g[u][i];
auto [v, c] = e[j];
if (c > 0 && h[v] == h[u] + 1) {
auto a = dfs(v, t, std::min(r, c));
e[j].cap -= a;
e[j ^ 1].cap += a;
r -= a;
if (r == 0) {
return f;
}
}
}
return f - r;
}
void addEdge(int u, int v, T c) {
g[u].push_back(e.size());
e.emplace_back(v, c);
g[v].push_back(e.size());
e.emplace_back(u, 0);
}
T flow(int s, int t) {
T ans = 0;
while (bfs(s, t)) {
cur.assign(n, 0);
ans += dfs(s, t, std::numeric_limits<T>::max());
}
return ans;
}
std::vector<bool> minCut() {
std::vector<bool> c(n);
for (int i = 0; i < n; i++) {
c[i] = (h[i] != -1);
}
return c;
}
struct Edge {
int from;
int to;
T cap;
T flow;
};
std::vector<Edge> edges() {
std::vector<Edge> a;
for (int i = 0; i < e.size(); i += 2) {
Edge x;
x.from = e[i + 1].to;
x.to = e[i].to;
x.cap = e[i].cap + e[i + 1].cap;
x.flow = e[i + 1].cap;
a.push_back(x);
}
return a;
}
};
待会自己写一个,用临界矩阵先写一个EK的
Dinic
对于FF的优化,由于FF每次都需要随机找到一条增广路径,而Dinic将图分层次之后,每次找增广路径只能找到这条路和下一条路的路径,这样极大优化了时间
1 | const int inf = 1e9 + 7; |
加入了当前弧优化, 使得效率更高
本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来源 梦始!
评论
