-
Notifications
You must be signed in to change notification settings - Fork 2
/
Copy pathedmond_karp.h
153 lines (127 loc) · 3 KB
/
edmond_karp.h
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
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
#ifndef EDMOND_KARP_H
#define EDMOND_KARP_H
#include "tiny_id_func.h"
#include "array_id_func.h"
namespace max_flow{
template<class InvTail, class Head, class BackArc, class Source, class Target>
BitIDFunc compute_maximum_unit_flow_using_edmond_karp(
const InvTail&inv_tail, const Head&head, const BackArc&back_arc,
const Source&source_list, const Target&target_list
){
int node_count = head.image_count();
int arc_count = head.preimage_count();
BitIDFunc is_target(node_count);
is_target.fill(false);
for(int i=0; i<target_list.preimage_count(); ++i)
is_target.set(target_list(i), true);
BitIDFunc is_source(node_count);
is_source.fill(false);
for(int i=0; i<source_list.preimage_count(); ++i)
is_source.set(source_list(i), true);
ArrayIDFunc<int> queue(node_count);
int queue_begin = 0;
int queue_end = 0;
BitIDFunc was_pushed(node_count);
auto advance_queue_pos = [&](int pos){
if(pos == node_count-1)
return 0;
else
return pos+1;
};
auto push = [&](int x){
queue[queue_end] = x;
queue_end = advance_queue_pos(queue_end);
was_pushed.set(x, true);
};
auto pop = [&]{
auto x = queue[queue_begin];
queue_begin = advance_queue_pos(queue_begin);
return x;
};
auto clear = [&]{
queue_begin = 0;
queue_end = 0;
was_pushed.fill(false);
};
auto is_empty = [&]{
return queue_begin == queue_end;
};
struct Pred{
int node;
int arc;
};
ArrayIDFunc<Pred> pred(node_count);
BitIDFunc flow(arc_count);
flow.fill(false);
auto find_augmenting_path = [&](int s){
clear();
push(s);
while(!is_empty()){
auto x = pop();
for(auto xy:inv_tail(x)){
if(!flow(xy)){
int y = head(xy);
if(!was_pushed(y) && !is_source(y)){
pred[y].node = x;
pred[y].arc = xy;
if(is_target(y)){
return y;
}else{
push(y);
}
}
}
}
}
return -1;
};
auto augment_flow_along_path = [&](int s, int y){
while(y != s){
auto x = pred(y).node;
auto xy = pred(y).arc;
auto yx = back_arc(xy);
assert(!flow(xy));
if(flow(yx))
flow.set(yx, false);
else
flow.set(xy, true);
y = x;
}
};
auto check_flow_invariants = [&]{
#ifndef NDEBUG
for(int i=0; i<arc_count; ++i)
assert(!flow(i) || !flow(back_arc(i)));
for(int x=0; x<node_count; ++x){
int surplus = 0;
for(int xy:inv_tail(x)){
if(flow(xy))
++surplus;
if(flow(back_arc(xy)))
--surplus;
}
if(is_source(x))
assert(surplus >= 0);
else if(is_target(x))
assert(surplus <= 0);
else
assert(surplus == 0);
}
for(int x=0; x<node_count; ++x)
assert(!is_source(x) || !is_target(x));
#endif
};
check_flow_invariants();
for(int i=0; i<source_list.preimage_count(); ++i){
auto s = source_list(i);
auto t = find_augmenting_path(s);
while(t != -1){
augment_flow_along_path(s, t);
check_flow_invariants();
t = find_augmenting_path(s);
}
}
return flow;
}
}
#endif