alpar@921
|
1 |
#ifndef LEMON_PREFLOW_PUSH_HH
|
alpar@921
|
2 |
#define LEMON_PREFLOW_PUSH_HH
|
athos@331
|
3 |
|
athos@331
|
4 |
//#include <algorithm>
|
athos@331
|
5 |
#include <list>
|
athos@331
|
6 |
#include <vector>
|
athos@331
|
7 |
#include <queue>
|
athos@331
|
8 |
//#include "pf_hiba.hh"
|
athos@331
|
9 |
//#include <marci_list_graph.hh>
|
athos@331
|
10 |
//#include <marci_graph_traits.hh>
|
athos@331
|
11 |
#include <invalid.h>
|
athos@331
|
12 |
//#include <reverse_bfs.hh>
|
athos@331
|
13 |
|
athos@331
|
14 |
using namespace std;
|
athos@331
|
15 |
|
alpar@921
|
16 |
namespace lemon {
|
athos@331
|
17 |
|
athos@331
|
18 |
template <typename Graph, typename T>
|
athos@331
|
19 |
class preflow_push {
|
athos@331
|
20 |
|
athos@331
|
21 |
//Useful typedefs
|
athos@331
|
22 |
typedef typename Graph::Node Node;
|
athos@331
|
23 |
typedef typename Graph::NodeIt NodeIt;
|
athos@331
|
24 |
typedef typename Graph::Edge Edge;
|
athos@331
|
25 |
typedef typename Graph::OutEdgeIt OutEdgeIt;
|
athos@331
|
26 |
typedef typename Graph::InEdgeIt InEdgeIt;
|
athos@331
|
27 |
|
athos@331
|
28 |
|
athos@331
|
29 |
//---------------------------------------------
|
athos@331
|
30 |
//Parameters of the algorithm
|
athos@331
|
31 |
//---------------------------------------------
|
athos@331
|
32 |
//Fully examine an active node until excess becomes 0
|
athos@331
|
33 |
enum node_examination_t {examine_full, examine_to_relabel};
|
athos@331
|
34 |
//No more implemented yet:, examine_only_one_edge};
|
athos@331
|
35 |
node_examination_t node_examination;
|
athos@331
|
36 |
//Which implementation to be used
|
athos@331
|
37 |
enum implementation_t {impl_fifo, impl_highest_label};
|
athos@331
|
38 |
//No more implemented yet:};
|
athos@331
|
39 |
implementation_t implementation;
|
athos@331
|
40 |
//---------------------------------------------
|
athos@331
|
41 |
//Parameters of the algorithm
|
athos@331
|
42 |
//---------------------------------------------
|
athos@331
|
43 |
|
athos@331
|
44 |
private:
|
athos@331
|
45 |
//input
|
athos@331
|
46 |
Graph& G;
|
athos@331
|
47 |
Node s;
|
athos@331
|
48 |
Node t;
|
athos@331
|
49 |
typename Graph::EdgeMap<T> &capacity;
|
athos@331
|
50 |
|
athos@331
|
51 |
//output
|
athos@331
|
52 |
typename Graph::EdgeMap<T> preflow;
|
athos@331
|
53 |
T maxflow_value;
|
athos@331
|
54 |
|
athos@331
|
55 |
//auxiliary variables for computation
|
athos@331
|
56 |
//The number of the nodes
|
athos@331
|
57 |
int number_of_nodes;
|
athos@331
|
58 |
//A nodemap for the level
|
athos@331
|
59 |
typename Graph::NodeMap<int> level;
|
athos@331
|
60 |
//A nodemap for the excess
|
athos@331
|
61 |
typename Graph::NodeMap<T> excess;
|
athos@331
|
62 |
|
athos@331
|
63 |
//Number of nodes on each level
|
athos@331
|
64 |
vector<int> num_of_nodes_on_level;
|
athos@331
|
65 |
|
athos@331
|
66 |
//For the FIFO implementation
|
athos@331
|
67 |
list<Node> fifo_nodes;
|
athos@331
|
68 |
//For 'highest label' implementation
|
athos@331
|
69 |
int highest_active;
|
athos@331
|
70 |
//int second_highest_active;
|
athos@331
|
71 |
vector< list<Node> > active_nodes;
|
athos@331
|
72 |
|
athos@331
|
73 |
public:
|
athos@331
|
74 |
|
athos@331
|
75 |
//Constructing the object using the graph, source, sink and capacity vector
|
athos@331
|
76 |
preflow_push(
|
athos@331
|
77 |
Graph& _G,
|
athos@331
|
78 |
Node _s,
|
athos@331
|
79 |
Node _t,
|
athos@331
|
80 |
typename Graph::EdgeMap<T> & _capacity)
|
athos@331
|
81 |
: G(_G), s(_s), t(_t),
|
athos@331
|
82 |
capacity(_capacity),
|
athos@331
|
83 |
preflow(_G),
|
athos@331
|
84 |
//Counting the number of nodes
|
athos@331
|
85 |
//number_of_nodes(count(G.first<EachNodeIt>())),
|
athos@331
|
86 |
number_of_nodes(G.nodeNum()),
|
athos@331
|
87 |
|
athos@331
|
88 |
level(_G),
|
athos@331
|
89 |
excess(_G)//,
|
athos@331
|
90 |
// Default constructor: active_nodes()
|
athos@331
|
91 |
{
|
athos@331
|
92 |
//Simplest parameter settings
|
athos@331
|
93 |
node_examination = examine_full;//examine_to_relabel;//
|
athos@331
|
94 |
//Which implementation to be usedexamine_full
|
athos@331
|
95 |
implementation = impl_highest_label;//impl_fifo;
|
athos@331
|
96 |
|
athos@331
|
97 |
//
|
athos@331
|
98 |
num_of_nodes_on_level.resize(2*number_of_nodes-1);
|
athos@331
|
99 |
num_of_nodes_on_level.clear();
|
athos@331
|
100 |
|
athos@331
|
101 |
switch(implementation){
|
athos@331
|
102 |
case impl_highest_label :{
|
athos@331
|
103 |
active_nodes.clear();
|
athos@331
|
104 |
active_nodes.resize(2*number_of_nodes-1);
|
athos@331
|
105 |
|
athos@331
|
106 |
break;
|
athos@331
|
107 |
}
|
athos@331
|
108 |
default:
|
athos@331
|
109 |
break;
|
athos@331
|
110 |
}
|
athos@331
|
111 |
|
athos@331
|
112 |
}
|
athos@331
|
113 |
|
athos@331
|
114 |
//Returns the value of a maximal flow
|
athos@331
|
115 |
T run();
|
athos@331
|
116 |
|
athos@331
|
117 |
typename Graph::EdgeMap<T> getmaxflow(){
|
athos@331
|
118 |
return preflow;
|
athos@331
|
119 |
}
|
athos@331
|
120 |
|
athos@331
|
121 |
|
athos@331
|
122 |
private:
|
athos@331
|
123 |
//For testing purposes only
|
athos@331
|
124 |
//Lists the node_properties
|
athos@331
|
125 |
void write_property_vector(typename Graph::NodeMap<T> a,
|
athos@331
|
126 |
//node_property_vector<Graph, T> a,
|
athos@331
|
127 |
char* prop_name="property"){
|
athos@331
|
128 |
for(NodeIt i=G.template first<NodeIt>(); G.valid(i); G.next(i)) {
|
athos@331
|
129 |
cout<<"Node id.: "<<G.id(i)<<", "<<prop_name<<" value: "<<a[i]<<endl;
|
athos@331
|
130 |
}
|
athos@331
|
131 |
cout<<endl;
|
athos@331
|
132 |
}
|
athos@331
|
133 |
|
athos@331
|
134 |
//Modifies the excess of the node and makes sufficient changes
|
athos@331
|
135 |
void modify_excess(const Node& a ,T v){
|
athos@331
|
136 |
//T old_value=excess[a];
|
athos@331
|
137 |
excess[a] += v;
|
athos@331
|
138 |
}
|
athos@331
|
139 |
|
athos@331
|
140 |
//This private procedure is supposed to modify the preflow on edge j
|
athos@331
|
141 |
//by value v (which can be positive or negative as well)
|
athos@331
|
142 |
//and maintain the excess on the head and tail
|
athos@331
|
143 |
//Here we do not check whether this is possible or not
|
athos@331
|
144 |
void modify_preflow(Edge j, const T& v){
|
athos@331
|
145 |
|
athos@331
|
146 |
//Modifiyng the edge
|
athos@331
|
147 |
preflow[j] += v;
|
athos@331
|
148 |
|
athos@331
|
149 |
|
athos@331
|
150 |
//Modifiyng the head
|
athos@331
|
151 |
modify_excess(G.head(j),v);
|
athos@331
|
152 |
|
athos@331
|
153 |
//Modifiyng the tail
|
athos@331
|
154 |
modify_excess(G.tail(j),-v);
|
athos@331
|
155 |
|
athos@331
|
156 |
}
|
athos@331
|
157 |
|
athos@331
|
158 |
//Gives the active node to work with
|
athos@331
|
159 |
//(depending on the implementation to be used)
|
athos@331
|
160 |
Node get_active_node(){
|
athos@331
|
161 |
|
athos@331
|
162 |
|
athos@331
|
163 |
switch(implementation) {
|
athos@331
|
164 |
case impl_highest_label : {
|
athos@331
|
165 |
|
athos@331
|
166 |
//First need to find the highest label for which there's an active node
|
athos@331
|
167 |
while( highest_active>=0 && active_nodes[highest_active].empty() ){
|
athos@331
|
168 |
--highest_active;
|
athos@331
|
169 |
}
|
athos@331
|
170 |
|
athos@331
|
171 |
if( highest_active>=0) {
|
athos@331
|
172 |
|
athos@331
|
173 |
|
athos@331
|
174 |
Node a=active_nodes[highest_active].front();
|
athos@331
|
175 |
active_nodes[highest_active].pop_front();
|
athos@331
|
176 |
|
athos@331
|
177 |
return a;
|
athos@331
|
178 |
}
|
athos@331
|
179 |
else {
|
athos@331
|
180 |
return INVALID;
|
athos@331
|
181 |
}
|
athos@331
|
182 |
|
athos@331
|
183 |
break;
|
athos@331
|
184 |
|
athos@331
|
185 |
}
|
athos@331
|
186 |
case impl_fifo : {
|
athos@331
|
187 |
|
athos@331
|
188 |
if( ! fifo_nodes.empty() ) {
|
athos@331
|
189 |
Node a=fifo_nodes.front();
|
athos@331
|
190 |
fifo_nodes.pop_front();
|
athos@331
|
191 |
return a;
|
athos@331
|
192 |
}
|
athos@331
|
193 |
else {
|
athos@331
|
194 |
return INVALID;
|
athos@331
|
195 |
}
|
athos@331
|
196 |
break;
|
athos@331
|
197 |
}
|
athos@331
|
198 |
}
|
athos@331
|
199 |
//
|
athos@331
|
200 |
return INVALID;
|
athos@331
|
201 |
}
|
athos@331
|
202 |
|
athos@331
|
203 |
//Puts node 'a' among the active nodes
|
athos@331
|
204 |
void make_active(const Node& a){
|
athos@331
|
205 |
//s and t never become active
|
athos@331
|
206 |
if (a!=s && a!= t){
|
athos@331
|
207 |
switch(implementation){
|
athos@331
|
208 |
case impl_highest_label :
|
athos@331
|
209 |
active_nodes[level[a]].push_back(a);
|
athos@331
|
210 |
break;
|
athos@331
|
211 |
case impl_fifo :
|
athos@331
|
212 |
fifo_nodes.push_back(a);
|
athos@331
|
213 |
break;
|
athos@331
|
214 |
}
|
athos@331
|
215 |
|
athos@331
|
216 |
}
|
athos@331
|
217 |
|
athos@331
|
218 |
//Update highest_active label
|
athos@331
|
219 |
if (highest_active<level[a]){
|
athos@331
|
220 |
highest_active=level[a];
|
athos@331
|
221 |
}
|
athos@331
|
222 |
|
athos@331
|
223 |
}
|
athos@331
|
224 |
|
athos@331
|
225 |
//Changes the level of node a and make sufficent changes
|
athos@331
|
226 |
void change_level_to(Node a, int new_value){
|
athos@331
|
227 |
int seged = level[a];
|
athos@331
|
228 |
level.set(a,new_value);
|
athos@331
|
229 |
--num_of_nodes_on_level[seged];
|
athos@331
|
230 |
++num_of_nodes_on_level[new_value];
|
athos@331
|
231 |
}
|
athos@331
|
232 |
|
athos@331
|
233 |
//Collection of things useful (or necessary) to do before running
|
athos@331
|
234 |
|
athos@331
|
235 |
void preprocess(){
|
athos@331
|
236 |
|
athos@331
|
237 |
//---------------------------------------
|
athos@331
|
238 |
//Initialize parameters
|
athos@331
|
239 |
//---------------------------------------
|
athos@331
|
240 |
|
athos@331
|
241 |
//Setting starting preflow, level and excess values to zero
|
athos@331
|
242 |
//This can be important, if the algorithm is run more then once
|
athos@331
|
243 |
for(NodeIt i=G.template first<NodeIt>(); G.valid(i); G.next(i)) {
|
athos@331
|
244 |
level.set(i,0);
|
athos@331
|
245 |
excess.set(i,0);
|
athos@331
|
246 |
for(OutEdgeIt j=G.template first<OutEdgeIt>(i); G.valid(j); G.next(j))
|
athos@331
|
247 |
preflow.set(j, 0);
|
athos@331
|
248 |
}
|
athos@331
|
249 |
num_of_nodes_on_level[0]=number_of_nodes;
|
athos@331
|
250 |
highest_active=0;
|
athos@331
|
251 |
//---------------------------------------
|
athos@331
|
252 |
//Initialize parameters
|
athos@331
|
253 |
//---------------------------------------
|
athos@331
|
254 |
|
athos@331
|
255 |
|
athos@331
|
256 |
//------------------------------------
|
athos@331
|
257 |
//This is the only part that uses BFS
|
athos@331
|
258 |
//------------------------------------
|
athos@331
|
259 |
|
athos@331
|
260 |
/*Reverse_bfs from t, to find the starting level.*/
|
athos@331
|
261 |
//Copyright: Jacint
|
athos@331
|
262 |
change_level_to(t,0);
|
athos@331
|
263 |
|
athos@331
|
264 |
std::queue<Node> bfs_queue;
|
athos@331
|
265 |
bfs_queue.push(t);
|
athos@331
|
266 |
|
athos@331
|
267 |
while (!bfs_queue.empty()) {
|
athos@331
|
268 |
|
athos@331
|
269 |
Node v=bfs_queue.front();
|
athos@331
|
270 |
bfs_queue.pop();
|
athos@331
|
271 |
int l=level[v]+1;
|
athos@331
|
272 |
|
athos@331
|
273 |
InEdgeIt e;
|
athos@331
|
274 |
for(G.first(e,v); G.valid(e); G.next(e)) {
|
athos@331
|
275 |
Node w=G.tail(e);
|
athos@331
|
276 |
if ( level[w] == number_of_nodes && w != s ) {
|
athos@331
|
277 |
bfs_queue.push(w);
|
athos@331
|
278 |
//Node first=level_list[l];
|
athos@331
|
279 |
//if ( G.valid(first) ) left.set(first,w);
|
athos@331
|
280 |
//right.set(w,first);
|
athos@331
|
281 |
//level_list[l]=w;
|
athos@331
|
282 |
change_level_to(w, l);
|
athos@331
|
283 |
//level.set(w, l);
|
athos@331
|
284 |
}
|
athos@331
|
285 |
}
|
athos@331
|
286 |
}
|
athos@331
|
287 |
change_level_to(s,number_of_nodes);
|
athos@331
|
288 |
//level.set(s,number_of_nodes);
|
athos@331
|
289 |
|
athos@331
|
290 |
/*
|
athos@331
|
291 |
//Setting starting level values using reverse bfs
|
athos@331
|
292 |
reverse_bfs<Graph> rev_bfs(G,t);
|
athos@331
|
293 |
rev_bfs.run();
|
athos@331
|
294 |
//write_property_vector(rev_bfs.dist,"rev_bfs");
|
athos@331
|
295 |
for(NodeIt i=G.template first<NodeIt>(); G.valid(i); G.next(i)) {
|
athos@331
|
296 |
change_level_to(i,rev_bfs.dist(i));
|
athos@331
|
297 |
//level.put(i,rev_bfs.dist.get(i));
|
athos@331
|
298 |
}
|
athos@331
|
299 |
*/
|
athos@331
|
300 |
//------------------------------------
|
athos@331
|
301 |
//This is the only part that uses BFS
|
athos@331
|
302 |
//------------------------------------
|
athos@331
|
303 |
|
athos@331
|
304 |
|
athos@331
|
305 |
//Starting level of s
|
athos@331
|
306 |
change_level_to(s,number_of_nodes);
|
athos@331
|
307 |
//level.put(s,number_of_nodes);
|
athos@331
|
308 |
|
athos@331
|
309 |
|
athos@331
|
310 |
//we push as much preflow from s as possible to start with
|
athos@331
|
311 |
for(OutEdgeIt j=G.template first<OutEdgeIt>(s); G.valid(j); G.next(j)){
|
athos@331
|
312 |
modify_preflow(j,capacity[j] );
|
athos@331
|
313 |
make_active(G.head(j));
|
athos@331
|
314 |
int lev=level[G.head(j)];
|
athos@331
|
315 |
if(highest_active<lev){
|
athos@331
|
316 |
highest_active=lev;
|
athos@331
|
317 |
}
|
athos@331
|
318 |
}
|
athos@331
|
319 |
//cout<<highest_active<<endl;
|
athos@331
|
320 |
}
|
athos@331
|
321 |
|
athos@331
|
322 |
|
athos@331
|
323 |
//If the preflow is less than the capacity on the given edge
|
athos@331
|
324 |
//then it is an edge in the residual graph
|
athos@331
|
325 |
bool is_admissible_forward_edge(Edge j, int& new_level){
|
athos@331
|
326 |
|
athos@331
|
327 |
if (capacity[j]>preflow[j]){
|
athos@331
|
328 |
if(level[G.tail(j)]==level[G.head(j)]+1){
|
athos@331
|
329 |
return true;
|
athos@331
|
330 |
}
|
athos@331
|
331 |
else{
|
athos@331
|
332 |
if (level[G.head(j)] < new_level)
|
athos@331
|
333 |
new_level=level[G.head(j)];
|
athos@331
|
334 |
}
|
athos@331
|
335 |
}
|
athos@331
|
336 |
return false;
|
athos@331
|
337 |
}
|
athos@331
|
338 |
|
athos@331
|
339 |
//If the preflow is greater than 0 on the given edge
|
athos@331
|
340 |
//then the edge reversd is an edge in the residual graph
|
athos@331
|
341 |
bool is_admissible_backward_edge(Edge j, int& new_level){
|
athos@331
|
342 |
|
athos@331
|
343 |
if (0<preflow[j]){
|
athos@331
|
344 |
if(level[G.tail(j)]==level[G.head(j)]-1){
|
athos@331
|
345 |
|
athos@331
|
346 |
return true;
|
athos@331
|
347 |
}
|
athos@331
|
348 |
else{
|
athos@331
|
349 |
if (level[G.tail(j)] < new_level)
|
athos@331
|
350 |
new_level=level[G.tail(j)];
|
athos@331
|
351 |
}
|
athos@331
|
352 |
|
athos@331
|
353 |
}
|
athos@331
|
354 |
return false;
|
athos@331
|
355 |
}
|
athos@331
|
356 |
|
athos@331
|
357 |
|
athos@331
|
358 |
}; //class preflow_push
|
athos@331
|
359 |
|
athos@331
|
360 |
template<typename Graph, typename T>
|
athos@331
|
361 |
T preflow_push<Graph, T>::run() {
|
athos@331
|
362 |
|
athos@331
|
363 |
preprocess();
|
athos@331
|
364 |
//write_property_vector(level,"level");
|
athos@331
|
365 |
T e,v;
|
athos@331
|
366 |
Node a;
|
athos@331
|
367 |
while (a=get_active_node(), G.valid(a)){
|
athos@331
|
368 |
|
athos@331
|
369 |
//cout<<G.id(a)<<endl;
|
athos@331
|
370 |
//write_property_vector(excess,"excess");
|
athos@331
|
371 |
//write_property_vector(level,"level");
|
athos@331
|
372 |
|
athos@331
|
373 |
|
athos@331
|
374 |
bool go_to_next_node=false;
|
athos@331
|
375 |
e = excess[a];
|
athos@331
|
376 |
while (!go_to_next_node){
|
athos@331
|
377 |
//Initial value for the new level for the active node we are dealing with
|
athos@331
|
378 |
int new_level=2*number_of_nodes;
|
athos@331
|
379 |
//write_property_vector(excess,"excess");
|
athos@331
|
380 |
//write_property_vector(level,"level");
|
athos@331
|
381 |
//cout<<G.id(a)<<endl;
|
athos@331
|
382 |
//Out edges from node a
|
athos@331
|
383 |
{
|
athos@331
|
384 |
OutEdgeIt j=G.template first<OutEdgeIt>(a);
|
athos@331
|
385 |
while (G.valid(j) && e){
|
athos@331
|
386 |
|
athos@331
|
387 |
if (is_admissible_forward_edge(j,new_level)){
|
athos@331
|
388 |
v=min(e,capacity[j] - preflow[j]);
|
athos@331
|
389 |
e -= v;
|
athos@331
|
390 |
//New node might become active
|
athos@331
|
391 |
if (excess[G.head(j)]==0){
|
athos@331
|
392 |
make_active(G.head(j));
|
athos@331
|
393 |
}
|
athos@331
|
394 |
modify_preflow(j,v);
|
athos@331
|
395 |
}
|
athos@331
|
396 |
G.next(j);
|
athos@331
|
397 |
}
|
athos@331
|
398 |
}
|
athos@331
|
399 |
//In edges to node a
|
athos@331
|
400 |
{
|
athos@331
|
401 |
InEdgeIt j=G.template first<InEdgeIt>(a);
|
athos@331
|
402 |
while (G.valid(j) && e){
|
athos@331
|
403 |
if (is_admissible_backward_edge(j,new_level)){
|
athos@331
|
404 |
v=min(e,preflow[j]);
|
athos@331
|
405 |
e -= v;
|
athos@331
|
406 |
//New node might become active
|
athos@331
|
407 |
if (excess[G.tail(j)]==0){
|
athos@331
|
408 |
make_active(G.tail(j));
|
athos@331
|
409 |
}
|
athos@331
|
410 |
modify_preflow(j,-v);
|
athos@331
|
411 |
}
|
athos@331
|
412 |
G.next(j);
|
athos@331
|
413 |
}
|
athos@331
|
414 |
}
|
athos@331
|
415 |
|
athos@331
|
416 |
//if (G.id(a)==999)
|
athos@331
|
417 |
//cout<<new_level<<" e: "<<e<<endl;
|
athos@331
|
418 |
//cout<<G.id(a)<<" "<<new_level<<endl;
|
athos@331
|
419 |
|
athos@331
|
420 |
if (0==e){
|
athos@331
|
421 |
//Saturating push
|
athos@331
|
422 |
go_to_next_node=true;
|
athos@331
|
423 |
}
|
athos@331
|
424 |
else{//If there is still excess in node a
|
athos@331
|
425 |
|
athos@331
|
426 |
//change_level_to(a,new_level+1);
|
athos@331
|
427 |
|
athos@331
|
428 |
//Level remains empty
|
athos@331
|
429 |
if (num_of_nodes_on_level[level[a]]==1){
|
athos@331
|
430 |
change_level_to(a,number_of_nodes);
|
athos@331
|
431 |
//go_to_next_node=True;
|
athos@331
|
432 |
}
|
athos@331
|
433 |
else{
|
athos@331
|
434 |
change_level_to(a,new_level+1);
|
athos@331
|
435 |
//increase_level(a);
|
athos@331
|
436 |
}
|
athos@331
|
437 |
|
athos@331
|
438 |
|
athos@331
|
439 |
|
athos@331
|
440 |
|
athos@331
|
441 |
switch(node_examination){
|
athos@331
|
442 |
case examine_to_relabel:
|
athos@331
|
443 |
make_active(a);
|
athos@331
|
444 |
|
athos@331
|
445 |
go_to_next_node = true;
|
athos@331
|
446 |
break;
|
athos@331
|
447 |
default:
|
athos@331
|
448 |
break;
|
athos@331
|
449 |
}
|
athos@331
|
450 |
|
athos@331
|
451 |
|
athos@331
|
452 |
|
athos@331
|
453 |
}//if (0==e)
|
athos@331
|
454 |
}
|
athos@331
|
455 |
}
|
athos@331
|
456 |
maxflow_value = excess[t];
|
athos@331
|
457 |
return maxflow_value;
|
athos@331
|
458 |
}//run
|
athos@331
|
459 |
|
athos@331
|
460 |
|
alpar@921
|
461 |
}//namespace lemon
|
athos@331
|
462 |
|
athos@331
|
463 |
#endif //PREFLOW_PUSH_HH
|