Small changes in the documentation.
3 * This file is a part of LEMON, a generic C++ optimization library
5 * Copyright (C) 2003-2007
6 * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport
7 * (Egervary Research Group on Combinatorial Optimization, EGRES).
9 * Permission to use, modify and distribute this software is granted
10 * provided that this copyright notice appears in all copies. For
11 * precise terms see the accompanying LICENSE file.
13 * This software is provided "AS IS" with no warranty of any kind,
14 * express or implied, and with no claim as to its suitability for any
19 #ifndef LEMON_GOLDBERG_TARJAN_H
20 #define LEMON_GOLDBERG_TARJAN_H
25 #include <lemon/error.h>
26 #include <lemon/bits/invalid.h>
27 #include <lemon/tolerance.h>
28 #include <lemon/maps.h>
29 #include <lemon/graph_utils.h>
30 #include <lemon/dynamic_tree.h>
35 /// \brief Implementation of the preflow algorithm.
39 /// \brief Default traits class of GoldbergTarjan class.
41 /// Default traits class of GoldbergTarjan class.
42 /// \param _Graph Graph type.
43 /// \param _CapacityMap Type of capacity map.
44 template <typename _Graph, typename _CapacityMap>
45 struct GoldbergTarjanDefaultTraits {
47 /// \brief The graph type the algorithm runs on.
50 /// \brief The type of the map that stores the edge capacities.
52 /// The type of the map that stores the edge capacities.
53 /// It must meet the \ref concepts::ReadMap "ReadMap" concept.
54 typedef _CapacityMap CapacityMap;
56 /// \brief The type of the length of the edges.
57 typedef typename CapacityMap::Value Value;
59 /// \brief The map type that stores the flow values.
61 /// The map type that stores the flow values.
62 /// It must meet the \ref concepts::ReadWriteMap "ReadWriteMap" concept.
63 typedef typename Graph::template EdgeMap<Value> FlowMap;
65 /// \brief Instantiates a FlowMap.
67 /// This function instantiates a \ref FlowMap.
68 /// \param graph The graph, to which we would like to define the flow map.
69 static FlowMap* createFlowMap(const Graph& graph) {
70 return new FlowMap(graph);
73 /// \brief The eleavator type used by GoldbergTarjan algorithm.
75 /// The elevator type used by GoldbergTarjan algorithm.
78 /// \sa LinkedElevator
79 typedef LinkedElevator<Graph, typename Graph::Node> Elevator;
81 /// \brief Instantiates an Elevator.
83 /// This function instantiates a \ref Elevator.
84 /// \param graph The graph, to which we would like to define the elevator.
85 /// \param max_level The maximum level of the elevator.
86 static Elevator* createElevator(const Graph& graph, int max_level) {
87 return new Elevator(graph, max_level);
90 /// \brief The tolerance used by the algorithm
92 /// The tolerance used by the algorithm to handle inexact computation.
93 typedef Tolerance<Value> Tolerance;
98 /// \brief Goldberg-Tarjan algorithms class.
100 /// This class provides an implementation of the \e GoldbergTarjan
101 /// \e algorithm producing a flow of maximum value in a directed
102 /// graph. The GoldbergTarjan algorithm is a theoretical improvement
103 /// of the Goldberg's \ref Preflow "preflow" algorithm by using the \ref
104 /// DynamicTree "dynamic tree" data structure of Sleator and Tarjan.
106 /// The original preflow algorithm with \e "highest label" or \e
107 /// FIFO heuristic has \f$O(n^3)\f$ time complexity. The current
108 /// algorithm improved this complexity to
109 /// \f$O(nm\log(\frac{n^2}{m}))\f$. The algorithm builds limited
110 /// size dynamic trees on the residual graph, which can be used to
111 /// make multilevel push operations and gives a better bound on the
112 /// number of non-saturating pushes.
114 /// \param Graph The directed graph type the algorithm runs on.
115 /// \param CapacityMap The capacity map type.
116 /// \param _Traits Traits class to set various data types used by
117 /// the algorithm. The default traits class is \ref
118 /// GoldbergTarjanDefaultTraits. See \ref
119 /// GoldbergTarjanDefaultTraits for the documentation of a
120 /// Goldberg-Tarjan traits class.
122 /// \author Tamas Hamori and Balazs Dezso
124 template <typename _Graph, typename _CapacityMap, typename _Traits>
126 template <typename _Graph,
127 typename _CapacityMap = typename _Graph::template EdgeMap<int>,
129 GoldbergTarjanDefaultTraits<_Graph, _CapacityMap> >
131 class GoldbergTarjan {
134 typedef _Traits Traits;
135 typedef typename Traits::Graph Graph;
136 typedef typename Traits::CapacityMap CapacityMap;
137 typedef typename Traits::Value Value;
139 typedef typename Traits::FlowMap FlowMap;
140 typedef typename Traits::Elevator Elevator;
141 typedef typename Traits::Tolerance Tolerance;
145 GRAPH_TYPEDEFS(typename Graph);
147 typedef typename Graph::template NodeMap<Node> NodeNodeMap;
148 typedef typename Graph::template NodeMap<int> IntNodeMap;
150 typedef typename Graph::template NodeMap<Edge> EdgeNodeMap;
151 typedef typename Graph::template EdgeMap<Edge> EdgeEdgeMap;
153 typedef typename std::vector<Node> VecNode;
155 typedef DynamicTree<Value,IntNodeMap,Tolerance> DynTree;
158 const CapacityMap* _capacity;
159 int _node_num; //the number of nodes of G
170 typedef typename Graph::template NodeMap<Value> ExcessMap;
173 Tolerance _tolerance;
177 // constant for treesize
178 static const double _tree_bound = 2;
181 //tags for the dynamic tree
183 //datastructure of dyanamic tree
184 IntNodeMap *_dt_index;
185 //datastrucure for solution of the communication between the two class
186 EdgeNodeMap *_dt_edges;
187 //nodeMap for storing the outgoing edge from the node in the tree
189 //max of the type Value
190 const Value _max_value;
194 typedef GoldbergTarjan Create;
196 ///\name Named template parameters
200 template <typename _FlowMap>
201 struct DefFlowMapTraits : public Traits {
202 typedef _FlowMap FlowMap;
203 static FlowMap *createFlowMap(const Graph&) {
204 throw UninitializedParameter();
208 /// \brief \ref named-templ-param "Named parameter" for setting
211 /// \ref named-templ-param "Named parameter" for setting FlowMap
213 template <typename _FlowMap>
215 : public GoldbergTarjan<Graph, CapacityMap,
216 DefFlowMapTraits<_FlowMap> > {
217 typedef GoldbergTarjan<Graph, CapacityMap,
218 DefFlowMapTraits<_FlowMap> > Create;
221 template <typename _Elevator>
222 struct DefElevatorTraits : public Traits {
223 typedef _Elevator Elevator;
224 static Elevator *createElevator(const Graph&, int) {
225 throw UninitializedParameter();
229 /// \brief \ref named-templ-param "Named parameter" for setting
232 /// \ref named-templ-param "Named parameter" for setting Elevator
234 template <typename _Elevator>
236 : public GoldbergTarjan<Graph, CapacityMap,
237 DefElevatorTraits<_Elevator> > {
238 typedef GoldbergTarjan<Graph, CapacityMap,
239 DefElevatorTraits<_Elevator> > Create;
242 template <typename _Elevator>
243 struct DefStandardElevatorTraits : public Traits {
244 typedef _Elevator Elevator;
245 static Elevator *createElevator(const Graph& graph, int max_level) {
246 return new Elevator(graph, max_level);
250 /// \brief \ref named-templ-param "Named parameter" for setting
253 /// \ref named-templ-param "Named parameter" for setting Elevator
254 /// type. The Elevator should be standard constructor interface, ie.
255 /// the graph and the maximum level should be passed to it.
256 template <typename _Elevator>
257 struct DefStandardElevator
258 : public GoldbergTarjan<Graph, CapacityMap,
259 DefStandardElevatorTraits<_Elevator> > {
260 typedef GoldbergTarjan<Graph, CapacityMap,
261 DefStandardElevatorTraits<_Elevator> > Create;
265 ///\ref Exception for the case when s=t.
267 ///\ref Exception for the case when the source equals the target.
268 class InvalidArgument : public lemon::LogicError {
270 virtual const char* what() const throw() {
271 return "lemon::GoldbergTarjan::InvalidArgument";
277 /// \brief The constructor of the class.
279 /// The constructor of the class.
280 /// \param graph The directed graph the algorithm runs on.
281 /// \param capacity The capacity of the edges.
282 /// \param source The source node.
283 /// \param target The target node.
284 /// Except the graph, all of these parameters can be reset by
285 /// calling \ref source, \ref target, \ref capacityMap and \ref
287 GoldbergTarjan(const Graph& graph, const CapacityMap& capacity,
288 Node source, Node target)
289 : _graph(graph), _capacity(&capacity),
290 _node_num(), _source(source), _target(target),
291 _flow(0), _local_flow(false),
292 _level(0), _local_level(false),
293 _excess(0), _tolerance(),
294 _phase(), _max_tree_size(),
295 _dt(0), _dt_index(0), _dt_edges(0),
296 _max_value(std::numeric_limits<Value>::max()) {
297 if (_source == _target) throw InvalidArgument();
300 /// \brief Destrcutor.
307 /// \brief Sets the capacity map.
309 /// Sets the capacity map.
310 /// \return \c (*this)
311 GoldbergTarjan& capacityMap(const CapacityMap& map) {
316 /// \brief Sets the flow map.
318 /// Sets the flow map.
319 /// \return \c (*this)
320 GoldbergTarjan& flowMap(FlowMap& map) {
329 /// \brief Returns the flow map.
331 /// \return The flow map.
332 const FlowMap& flowMap() {
336 /// \brief Sets the elevator.
338 /// Sets the elevator.
339 /// \return \c (*this)
340 GoldbergTarjan& elevator(Elevator& elevator) {
343 _local_level = false;
349 /// \brief Returns the elevator.
351 /// \return The elevator.
352 const Elevator& elevator() {
356 /// \brief Sets the source node.
358 /// Sets the source node.
359 /// \return \c (*this)
360 GoldbergTarjan& source(const Node& node) {
365 /// \brief Sets the target node.
367 /// Sets the target node.
368 /// \return \c (*this)
369 GoldbergTarjan& target(const Node& node) {
374 /// \brief Sets the tolerance used by algorithm.
376 /// Sets the tolerance used by algorithm.
377 GoldbergTarjan& tolerance(const Tolerance& tolerance) const {
378 _tolerance = tolerance;
380 _dt->tolerance(_tolerance);
385 /// \brief Returns the tolerance used by algorithm.
387 /// Returns the tolerance used by algorithm.
388 const Tolerance& tolerance() const {
395 void createStructures() {
396 _node_num = countNodes(_graph);
398 _max_tree_size = (double(_node_num) * double(_node_num)) /
399 double(countEdges(_graph));
402 _flow = Traits::createFlowMap(_graph);
406 _level = Traits::createElevator(_graph, _node_num);
410 _excess = new ExcessMap(_graph);
412 if (!_dt_index && !_dt) {
413 _dt_index = new IntNodeMap(_graph);
414 _dt = new DynTree(*_dt_index, _tolerance);
417 _dt_edges = new EdgeNodeMap(_graph);
421 void destroyStructures() {
442 bool sendOut(Node n, Value& excess) {
444 Node w = _dt->findRoot(n);
449 Node u = _dt->findCost(n, rem);
451 if (_tolerance.positive(rem) && !_level->active(w) && w != _target) {
455 if (!_tolerance.less(rem, excess)) {
456 _dt->addCost(n, - excess);
457 _excess->set(w, (*_excess)[w] + excess);
463 _dt->addCost(n, - rem);
466 _excess->set(w, (*_excess)[w] + rem);
469 _dt->addCost(u, _max_value);
471 Edge e = (*_dt_edges)[u];
472 _dt_edges->set(u, INVALID);
474 if (u == _graph.source(e)) {
475 _flow->set(e, (*_capacity)[e]);
480 w = _dt->findRoot(n);
485 bool sendIn(Node n, Value& excess) {
487 Node w = _dt->findRoot(n);
492 Node u = _dt->findCost(n, rem);
494 if (_tolerance.positive(rem) && !_level->active(w) && w != _source) {
498 if (!_tolerance.less(rem, excess)) {
499 _dt->addCost(n, - excess);
500 _excess->set(w, (*_excess)[w] + excess);
506 _dt->addCost(n, - rem);
509 _excess->set(w, (*_excess)[w] + rem);
512 _dt->addCost(u, _max_value);
514 Edge e = (*_dt_edges)[u];
515 _dt_edges->set(u, INVALID);
517 if (u == _graph.source(e)) {
518 _flow->set(e, (*_capacity)[e]);
523 w = _dt->findRoot(n);
528 void cutChildren(Node n) {
530 for (OutEdgeIt e(_graph, n); e != INVALID; ++e) {
532 Node v = _graph.target(e);
534 if ((*_dt_edges)[v] != INVALID && (*_dt_edges)[v] == e) {
536 _dt_edges->set(v, INVALID);
538 _dt->findCost(v, rem);
539 _dt->addCost(v, - rem);
540 _dt->addCost(v, _max_value);
546 for (InEdgeIt e(_graph, n); e != INVALID; ++e) {
548 Node v = _graph.source(e);
550 if ((*_dt_edges)[v] != INVALID && (*_dt_edges)[v] == e) {
552 _dt_edges->set(v, INVALID);
554 _dt->findCost(v, rem);
555 _dt->addCost(v, - rem);
556 _dt->addCost(v, _max_value);
557 _flow->set(e, (*_capacity)[e] - rem);
563 void extractTrees() {
564 for (NodeIt n(_graph); n != INVALID; ++n) {
566 Node w = _dt->findRoot(n);
571 Node u = _dt->findCost(n, rem);
574 _dt->addCost(u, - rem);
575 _dt->addCost(u, _max_value);
577 Edge e = (*_dt_edges)[u];
578 _dt_edges->set(u, INVALID);
580 if (u == _graph.source(e)) {
581 _flow->set(e, (*_capacity)[e] - rem);
586 w = _dt->findRoot(n);
593 /// \name Execution control The simplest way to execute the
594 /// algorithm is to use one of the member functions called \c
597 /// If you need more control on initial solution or
598 /// execution then you have to call one \ref init() function and then
599 /// the startFirstPhase() and if you need the startSecondPhase().
603 /// \brief Initializes the internal data structures.
605 /// Initializes the internal data structures.
610 for (NodeIt n(_graph); n != INVALID; ++n) {
614 for (EdgeIt e(_graph); e != INVALID; ++e) {
619 for (NodeIt v(_graph); v != INVALID; ++v) {
620 (*_dt_edges)[v] = INVALID;
622 _dt->addCost(v, _max_value);
625 typename Graph::template NodeMap<bool> reached(_graph, false);
628 _level->initAddItem(_target);
630 std::vector<Node> queue;
631 reached.set(_source, true);
633 queue.push_back(_target);
634 reached.set(_target, true);
635 while (!queue.empty()) {
636 _level->initNewLevel();
637 std::vector<Node> nqueue;
638 for (int i = 0; i < int(queue.size()); ++i) {
640 for (InEdgeIt e(_graph, n); e != INVALID; ++e) {
641 Node u = _graph.source(e);
642 if (!reached[u] && _tolerance.positive((*_capacity)[e])) {
643 reached.set(u, true);
644 _level->initAddItem(u);
651 _level->initFinish();
653 for (OutEdgeIt e(_graph, _source); e != INVALID; ++e) {
654 if (_tolerance.positive((*_capacity)[e])) {
655 Node u = _graph.target(e);
656 if ((*_level)[u] == _level->maxLevel()) continue;
657 _flow->set(e, (*_capacity)[e]);
658 _excess->set(u, (*_excess)[u] + (*_capacity)[e]);
659 if (u != _target && !_level->active(u)) {
666 /// \brief Starts the first phase of the preflow algorithm.
668 /// The preflow algorithm consists of two phases, this method runs
669 /// the first phase. After the first phase the maximum flow value
670 /// and a minimum value cut can already be computed, although a
671 /// maximum flow is not yet obtained. So after calling this method
672 /// \ref flowValue() returns the value of a maximum flow and \ref
673 /// minCut() returns a minimum cut.
674 /// \pre One of the \ref init() functions should be called.
675 void startFirstPhase() {
679 while ((n = _level->highestActive()) != INVALID) {
680 Value excess = (*_excess)[n];
681 int level = _level->highestActiveLevel();
682 int new_level = _level->maxLevel();
684 if (_dt->findRoot(n) != n) {
685 if (sendOut(n, excess)) goto no_more_push;
688 for (OutEdgeIt e(_graph, n); e != INVALID; ++e) {
689 Value rem = (*_capacity)[e] - (*_flow)[e];
690 Node v = _graph.target(e);
692 if (!_tolerance.positive(rem) && (*_dt_edges)[v] != e) continue;
694 if ((*_level)[v] < level) {
696 if (_dt->findSize(n) + _dt->findSize(v) <
697 _tree_bound * _max_tree_size) {
698 _dt->addCost(n, -_max_value);
699 _dt->addCost(n, rem);
701 _dt_edges->set(n, e);
702 if (sendOut(n, excess)) goto no_more_push;
704 if (!_level->active(v) && v != _target) {
707 if (!_tolerance.less(rem, excess)) {
708 _flow->set(e, (*_flow)[e] + excess);
709 _excess->set(v, (*_excess)[v] + excess);
714 _excess->set(v, (*_excess)[v] + rem);
715 _flow->set(e, (*_capacity)[e]);
718 } else if (new_level > (*_level)[v]) {
719 new_level = (*_level)[v];
723 for (InEdgeIt e(_graph, n); e != INVALID; ++e) {
724 Value rem = (*_flow)[e];
725 Node v = _graph.source(e);
726 if (!_tolerance.positive(rem) && (*_dt_edges)[v] != e) continue;
728 if ((*_level)[v] < level) {
730 if (_dt->findSize(n) + _dt->findSize(v) <
731 _tree_bound * _max_tree_size) {
732 _dt->addCost(n, - _max_value);
733 _dt->addCost(n, rem);
735 _dt_edges->set(n, e);
736 if (sendOut(n, excess)) goto no_more_push;
738 if (!_level->active(v) && v != _target) {
741 if (!_tolerance.less(rem, excess)) {
742 _flow->set(e, (*_flow)[e] - excess);
743 _excess->set(v, (*_excess)[v] + excess);
748 _excess->set(v, (*_excess)[v] + rem);
752 } else if (new_level > (*_level)[v]) {
753 new_level = (*_level)[v];
759 _excess->set(n, excess);
763 if (new_level + 1 < _level->maxLevel()) {
764 _level->liftHighestActive(new_level + 1);
766 _level->liftHighestActiveToTop();
768 if (_level->emptyLevel(level)) {
769 _level->liftToTop(level);
772 _level->deactivate(n);
778 /// \brief Starts the second phase of the preflow algorithm.
780 /// The preflow algorithm consists of two phases, this method runs
781 /// the second phase. After calling \ref init() and \ref
782 /// startFirstPhase() and then \ref startSecondPhase(), \ref
783 /// flowMap() return a maximum flow, \ref flowValue() returns the
784 /// value of a maximum flow, \ref minCut() returns a minimum cut
785 /// \pre The \ref init() and startFirstPhase() functions should be
787 void startSecondPhase() {
790 typename Graph::template NodeMap<bool> reached(_graph, false);
791 for (NodeIt n(_graph); n != INVALID; ++n) {
792 reached.set(n, (*_level)[n] < _level->maxLevel());
796 _level->initAddItem(_source);
798 std::vector<Node> queue;
799 queue.push_back(_source);
800 reached.set(_source, true);
802 while (!queue.empty()) {
803 _level->initNewLevel();
804 std::vector<Node> nqueue;
805 for (int i = 0; i < int(queue.size()); ++i) {
807 for (OutEdgeIt e(_graph, n); e != INVALID; ++e) {
808 Node v = _graph.target(e);
809 if (!reached[v] && _tolerance.positive((*_flow)[e])) {
810 reached.set(v, true);
811 _level->initAddItem(v);
815 for (InEdgeIt e(_graph, n); e != INVALID; ++e) {
816 Node u = _graph.source(e);
818 _tolerance.positive((*_capacity)[e] - (*_flow)[e])) {
819 reached.set(u, true);
820 _level->initAddItem(u);
827 _level->initFinish();
829 for (NodeIt n(_graph); n != INVALID; ++n) {
830 if ((*_excess)[n] > 0 && _target != n) {
837 while ((n = _level->highestActive()) != INVALID) {
838 Value excess = (*_excess)[n];
839 int level = _level->highestActiveLevel();
840 int new_level = _level->maxLevel();
842 if (_dt->findRoot(n) != n) {
843 if (sendIn(n, excess)) goto no_more_push;
846 for (OutEdgeIt e(_graph, n); e != INVALID; ++e) {
847 Value rem = (*_capacity)[e] - (*_flow)[e];
848 Node v = _graph.target(e);
850 if (!_tolerance.positive(rem) && (*_dt_edges)[v] != e) continue;
852 if ((*_level)[v] < level) {
854 if (_dt->findSize(n) + _dt->findSize(v) <
855 _tree_bound * _max_tree_size) {
856 _dt->addCost(n, -_max_value);
857 _dt->addCost(n, rem);
859 _dt_edges->set(n, e);
860 if (sendIn(n, excess)) goto no_more_push;
862 if (!_level->active(v) && v != _source) {
865 if (!_tolerance.less(rem, excess)) {
866 _flow->set(e, (*_flow)[e] + excess);
867 _excess->set(v, (*_excess)[v] + excess);
872 _excess->set(v, (*_excess)[v] + rem);
873 _flow->set(e, (*_capacity)[e]);
876 } else if (new_level > (*_level)[v]) {
877 new_level = (*_level)[v];
881 for (InEdgeIt e(_graph, n); e != INVALID; ++e) {
882 Value rem = (*_flow)[e];
883 Node v = _graph.source(e);
884 if (!_tolerance.positive(rem) && (*_dt_edges)[v] != e) continue;
886 if ((*_level)[v] < level) {
888 if (_dt->findSize(n) + _dt->findSize(v) <
889 _tree_bound * _max_tree_size) {
890 _dt->addCost(n, - _max_value);
891 _dt->addCost(n, rem);
893 _dt_edges->set(n, e);
894 if (sendIn(n, excess)) goto no_more_push;
896 if (!_level->active(v) && v != _source) {
899 if (!_tolerance.less(rem, excess)) {
900 _flow->set(e, (*_flow)[e] - excess);
901 _excess->set(v, (*_excess)[v] + excess);
906 _excess->set(v, (*_excess)[v] + rem);
910 } else if (new_level > (*_level)[v]) {
911 new_level = (*_level)[v];
917 _excess->set(n, excess);
921 if (new_level + 1 < _level->maxLevel()) {
922 _level->liftHighestActive(new_level + 1);
924 _level->liftHighestActiveToTop();
926 if (_level->emptyLevel(level)) {
927 _level->liftToTop(level);
930 _level->deactivate(n);
936 /// \brief Runs the Goldberg-Tarjan algorithm.
938 /// Runs the Goldberg-Tarjan algorithm.
939 /// \note pf.run() is just a shortcut of the following code.
942 /// pf.startFirstPhase();
943 /// pf.startSecondPhase();
951 /// \brief Runs the Goldberg-Tarjan algorithm to compute the minimum cut.
953 /// Runs the Goldberg-Tarjan algorithm to compute the minimum cut.
954 /// \note pf.runMinCut() is just a shortcut of the following code.
957 /// pf.startFirstPhase();
966 /// \name Query Functions
967 /// The result of the %Dijkstra algorithm can be obtained using these
969 /// Before the use of these functions,
970 /// either run() or start() must be called.
974 /// \brief Returns the value of the maximum flow.
976 /// Returns the value of the maximum flow by returning the excess
977 /// of the target node \c t. This value equals to the value of
978 /// the maximum flow already after the first phase.
979 Value flowValue() const {
980 return (*_excess)[_target];
983 /// \brief Returns true when the node is on the source side of minimum cut.
985 /// Returns true when the node is on the source side of minimum
986 /// cut. This method can be called both after running \ref
987 /// startFirstPhase() and \ref startSecondPhase().
988 bool minCut(const Node& node) const {
989 return ((*_level)[node] == _level->maxLevel()) == _phase;
992 /// \brief Returns a minimum value cut.
994 /// Sets the \c cutMap to the characteristic vector of a minimum value
995 /// cut. This method can be called both after running \ref
996 /// startFirstPhase() and \ref startSecondPhase(). The result after second
997 /// phase could be changed slightly if inexact computation is used.
998 /// \pre The \c cutMap should be a bool-valued node-map.
999 template <typename CutMap>
1000 void minCutMap(CutMap& cutMap) const {
1001 for (NodeIt n(_graph); n != INVALID; ++n) {
1002 cutMap.set(n, minCut(n));
1006 /// \brief Returns the flow on the edge.
1008 /// Sets the \c flowMap to the flow on the edges. This method can
1009 /// be called after the second phase of algorithm.
1010 Value flow(const Edge& edge) const {
1011 return (*_flow)[edge];