lemon/hao_orlin.h
author athos
Mon, 30 Oct 2006 16:26:13 +0000
changeset 2275 ff46747676ed
parent 2273 507232469f5e
child 2340 03c71d754990
permissions -rw-r--r--
Small bugs in the documentation 2.
     1 /* -*- C++ -*-
     2  *
     3  * This file is a part of LEMON, a generic C++ optimization library
     4  *
     5  * Copyright (C) 2003-2006
     6  * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport
     7  * (Egervary Research Group on Combinatorial Optimization, EGRES).
     8  *
     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.
    12  *
    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
    15  * purpose.
    16  *
    17  */
    18 
    19 #ifndef LEMON_HAO_ORLIN_H
    20 #define LEMON_HAO_ORLIN_H
    21 
    22 #include <vector>
    23 #include <queue>
    24 #include <limits>
    25 
    26 #include <lemon/maps.h>
    27 #include <lemon/graph_utils.h>
    28 #include <lemon/graph_adaptor.h>
    29 #include <lemon/iterable_maps.h>
    30  
    31 
    32 /// \file
    33 /// \ingroup flowalgs
    34 /// \brief Implementation of the Hao-Orlin algorithm.
    35 ///
    36 /// Implementation of the HaoOrlin algorithms class for testing network 
    37 /// reliability.
    38 
    39 namespace lemon {
    40 
    41   /// \ingroup flowalgs
    42   ///
    43   /// \brief %Hao-Orlin algorithm to find a minimum cut in directed graphs.
    44   ///
    45   /// Hao-Orlin calculates a minimum cut in a directed graph 
    46   /// \f$ D=(V,A) \f$. It takes a fixed node \f$ source \in V \f$ and consists
    47   /// of two phases: in the first phase it determines a minimum cut
    48   /// with \f$ source \f$ on the source-side (i.e. a set \f$ X\subsetneq V \f$
    49   /// with \f$ source \in X \f$ and minimal out-degree) and in the
    50   /// second phase it determines a minimum cut with \f$ source \f$ on the
    51   /// sink-side (i.e. a set \f$ X\subsetneq V \f$ with \f$ source \notin X \f$
    52   /// and minimal out-degree). Obviously, the smaller of these two
    53   /// cuts will be a minimum cut of \f$ D \f$. The algorithm is a
    54   /// modified push-relabel preflow algorithm and our implementation
    55   /// calculates the minimum cut in \f$ O(n^3) \f$ time (we use the
    56   /// highest-label rule). The purpose of such an algorithm is testing
    57   /// network reliability. For an undirected graph with \f$ n \f$
    58   /// nodes and \f$ e \f$ edges you can use the algorithm of Nagamochi
    59   /// and Ibaraki which solves the undirected problem in 
    60   /// \f$ O(ne + n^2 \log(n)) \f$ time: it is implemented in the MinCut 
    61   /// algorithm
    62   /// class.
    63   ///
    64   /// \param _Graph is the graph type of the algorithm.
    65   /// \param _CapacityMap is an edge map of capacities which should
    66   /// be any numreric type. The default type is _Graph::EdgeMap<int>.
    67   /// \param _Tolerance is the handler of the inexact computation. The
    68   /// default type for this is Tolerance<typename CapacityMap::Value>.
    69   ///
    70   /// \author Attila Bernath and Balazs Dezso
    71 #ifdef DOXYGEN
    72   template <typename _Graph, typename _CapacityMap, typename _Tolerance>
    73 #else
    74   template <typename _Graph,
    75 	    typename _CapacityMap = typename _Graph::template EdgeMap<int>,
    76             typename _Tolerance = Tolerance<typename _CapacityMap::Value> >
    77 #endif
    78   class HaoOrlin {
    79   protected:
    80 
    81     typedef _Graph Graph;
    82     typedef _CapacityMap CapacityMap;
    83     typedef _Tolerance Tolerance;
    84 
    85     typedef typename CapacityMap::Value Value;
    86 
    87     
    88     typedef typename Graph::Node Node;
    89     typedef typename Graph::NodeIt NodeIt;
    90     typedef typename Graph::EdgeIt EdgeIt;
    91     typedef typename Graph::OutEdgeIt OutEdgeIt;
    92     typedef typename Graph::InEdgeIt InEdgeIt;
    93 
    94     const Graph* _graph;
    95 
    96     const CapacityMap* _capacity;
    97 
    98     typedef typename Graph::template EdgeMap<Value> FlowMap;
    99 
   100     FlowMap* _preflow;
   101 
   102     Node _source, _target;
   103     int _node_num;
   104 
   105     typedef ResGraphAdaptor<const Graph, Value, CapacityMap, 
   106                             FlowMap, Tolerance> OutResGraph;
   107     typedef typename OutResGraph::Edge OutResEdge;
   108     
   109     OutResGraph* _out_res_graph;
   110 
   111     typedef typename Graph::template NodeMap<OutResEdge> OutCurrentEdgeMap;
   112     OutCurrentEdgeMap* _out_current_edge;  
   113 
   114     typedef RevGraphAdaptor<const Graph> RevGraph;
   115     RevGraph* _rev_graph;
   116 
   117     typedef ResGraphAdaptor<const RevGraph, Value, CapacityMap, 
   118                             FlowMap, Tolerance> InResGraph;
   119     typedef typename InResGraph::Edge InResEdge;
   120     
   121     InResGraph* _in_res_graph;
   122 
   123     typedef typename Graph::template NodeMap<InResEdge> InCurrentEdgeMap;
   124     InCurrentEdgeMap* _in_current_edge;  
   125 
   126 
   127     typedef IterableBoolMap<Graph, Node> WakeMap;
   128     WakeMap* _wake;
   129 
   130     typedef typename Graph::template NodeMap<int> DistMap;
   131     DistMap* _dist;  
   132     
   133     typedef typename Graph::template NodeMap<Value> ExcessMap;
   134     ExcessMap* _excess;
   135 
   136     typedef typename Graph::template NodeMap<bool> SourceSetMap;
   137     SourceSetMap* _source_set;
   138 
   139     std::vector<int> _level_size;
   140 
   141     int _highest_active;
   142     std::vector<std::list<Node> > _active_nodes;
   143 
   144     int _dormant_max;
   145     std::vector<std::list<Node> > _dormant;
   146 
   147 
   148     Value _min_cut;
   149 
   150     typedef typename Graph::template NodeMap<bool> MinCutMap;
   151     MinCutMap* _min_cut_map;
   152 
   153     Tolerance _tolerance;
   154 
   155   public: 
   156 
   157     /// \brief Constructor
   158     ///
   159     /// Constructor of the algorithm class. 
   160     HaoOrlin(const Graph& graph, const CapacityMap& capacity, 
   161              const Tolerance& tolerance = Tolerance()) :
   162       _graph(&graph), _capacity(&capacity), 
   163       _preflow(0), _source(), _target(), 
   164       _out_res_graph(0), _out_current_edge(0),
   165       _rev_graph(0), _in_res_graph(0), _in_current_edge(0),
   166       _wake(0),_dist(0), _excess(0), _source_set(0), 
   167       _highest_active(), _active_nodes(), _dormant_max(), _dormant(), 
   168       _min_cut(), _min_cut_map(0), _tolerance(tolerance) {}
   169 
   170     ~HaoOrlin() {
   171       if (_min_cut_map) {
   172         delete _min_cut_map;
   173       } 
   174       if (_in_current_edge) {
   175         delete _in_current_edge;
   176       }
   177       if (_in_res_graph) {
   178         delete _in_res_graph;
   179       }
   180       if (_rev_graph) {
   181         delete _rev_graph;
   182       }
   183       if (_out_current_edge) {
   184         delete _out_current_edge;
   185       }
   186       if (_out_res_graph) {
   187         delete _out_res_graph;
   188       }
   189       if (_source_set) {
   190         delete _source_set;
   191       }
   192       if (_excess) {
   193         delete _excess;
   194       }
   195       if (_dist) {
   196         delete _dist;
   197       }
   198       if (_wake) {
   199         delete _wake;
   200       }
   201       if (_preflow) {
   202         delete _preflow;
   203       }
   204     }
   205     
   206   private:
   207     
   208     template <typename ResGraph, typename EdgeMap>
   209     void findMinCut(const Node& target, bool out, 
   210                     ResGraph& res_graph, EdgeMap& current_edge) {
   211       typedef typename ResGraph::Edge ResEdge;
   212       typedef typename ResGraph::OutEdgeIt ResOutEdgeIt;
   213 
   214       for (typename Graph::EdgeIt it(*_graph); it != INVALID; ++it) {
   215         (*_preflow)[it] = 0;      
   216       }
   217       for (NodeIt it(*_graph); it != INVALID; ++it) {
   218         (*_wake)[it] = true;
   219         (*_dist)[it] = 1;
   220         (*_excess)[it] = 0;
   221         (*_source_set)[it] = false;
   222 
   223         res_graph.firstOut(current_edge[it], it);
   224       }
   225 
   226       _target = target;
   227       (*_dist)[target] = 0;
   228 
   229       for (ResOutEdgeIt it(res_graph, _source); it != INVALID; ++it) {
   230         Value delta = res_graph.rescap(it);
   231         if (!_tolerance.positive(delta)) continue;
   232         
   233         (*_excess)[res_graph.source(it)] -= delta;
   234         res_graph.augment(it, delta);
   235         Node a = res_graph.target(it);
   236         if (!_tolerance.positive((*_excess)[a]) && 
   237             (*_wake)[a] && a != _target) {
   238           _active_nodes[(*_dist)[a]].push_front(a);
   239           if (_highest_active < (*_dist)[a]) {
   240             _highest_active = (*_dist)[a];
   241           }
   242         }
   243         (*_excess)[a] += delta;
   244       }
   245 
   246       _dormant[0].push_front(_source);
   247       (*_source_set)[_source] = true;
   248       _dormant_max = 0;
   249       (*_wake)[_source] = false;
   250 
   251       _level_size[0] = 1;
   252       _level_size[1] = _node_num - 1;
   253 
   254       do {
   255 	Node n;
   256 	while ((n = findActiveNode()) != INVALID) {
   257 	  ResEdge e;
   258 	  while (_tolerance.positive((*_excess)[n]) && 
   259                  (e = findAdmissibleEdge(n, res_graph, current_edge)) 
   260                  != INVALID){
   261 	    Value delta;
   262 	    if ((*_excess)[n] < res_graph.rescap(e)) {
   263 	      delta = (*_excess)[n];
   264 	    } else {
   265 	      delta = res_graph.rescap(e);
   266 	      res_graph.nextOut(current_edge[n]);
   267 	    }
   268             if (!_tolerance.positive(delta)) continue;
   269 	    res_graph.augment(e, delta);
   270 	    (*_excess)[res_graph.source(e)] -= delta;
   271 	    Node a = res_graph.target(e);
   272 	    if (!_tolerance.positive((*_excess)[a]) && a != _target) {
   273 	      _active_nodes[(*_dist)[a]].push_front(a);
   274 	    }
   275 	    (*_excess)[a] += delta;
   276 	  }
   277 	  if (_tolerance.positive((*_excess)[n])) {
   278 	    relabel(n, res_graph, current_edge);
   279           }
   280 	}
   281 
   282 	Value current_value = cutValue(out);
   283  	if (_min_cut > current_value){
   284           if (out) {
   285             for (NodeIt it(*_graph); it != INVALID; ++it) {
   286               _min_cut_map->set(it, !(*_wake)[it]);
   287             } 
   288           } else {
   289             for (NodeIt it(*_graph); it != INVALID; ++it) {
   290               _min_cut_map->set(it, (*_wake)[it]);
   291             } 
   292           }
   293 
   294 	  _min_cut = current_value;
   295  	}
   296 
   297       } while (selectNewSink(res_graph));
   298     }
   299 
   300     template <typename ResGraph, typename EdgeMap>
   301     void relabel(const Node& n, ResGraph& res_graph, EdgeMap& current_edge) {
   302       typedef typename ResGraph::OutEdgeIt ResOutEdgeIt;
   303 
   304       int k = (*_dist)[n];
   305       if (_level_size[k] == 1) {
   306 	++_dormant_max;
   307 	for (NodeIt it(*_graph); it != INVALID; ++it) {
   308 	  if ((*_wake)[it] && (*_dist)[it] >= k) {
   309 	    (*_wake)[it] = false;
   310 	    _dormant[_dormant_max].push_front(it);
   311 	    --_level_size[(*_dist)[it]];
   312 	  }
   313 	}
   314 	--_highest_active;
   315       } else {	
   316         int new_dist = _node_num;
   317         for (ResOutEdgeIt e(res_graph, n); e != INVALID; ++e) {
   318           Node t = res_graph.target(e);
   319           if ((*_wake)[t] && new_dist > (*_dist)[t]) {
   320             new_dist = (*_dist)[t];
   321           }
   322         }
   323         if (new_dist == _node_num) {
   324 	  ++_dormant_max;
   325 	  (*_wake)[n] = false;
   326 	  _dormant[_dormant_max].push_front(n);
   327 	  --_level_size[(*_dist)[n]];
   328 	} else {	    
   329 	  --_level_size[(*_dist)[n]];
   330 	  (*_dist)[n] = new_dist + 1;
   331 	  _highest_active = (*_dist)[n];
   332 	  _active_nodes[_highest_active].push_front(n);
   333 	  ++_level_size[(*_dist)[n]];
   334 	  res_graph.firstOut(current_edge[n], n);
   335 	}
   336       }
   337     }
   338 
   339     template <typename ResGraph>
   340     bool selectNewSink(ResGraph& res_graph) {
   341       typedef typename ResGraph::OutEdgeIt ResOutEdgeIt;
   342 
   343       Node old_target = _target;
   344       (*_wake)[_target] = false;
   345       --_level_size[(*_dist)[_target]];
   346       _dormant[0].push_front(_target);
   347       (*_source_set)[_target] = true;
   348       if ((int)_dormant[0].size() == _node_num){
   349         _dormant[0].clear();
   350 	return false;
   351       }
   352 
   353       bool wake_was_empty = false;
   354 
   355       if(_wake->trueNum() == 0) {
   356 	while (!_dormant[_dormant_max].empty()){
   357 	  (*_wake)[_dormant[_dormant_max].front()] = true;
   358 	  ++_level_size[(*_dist)[_dormant[_dormant_max].front()]];
   359 	  _dormant[_dormant_max].pop_front();
   360 	}
   361 	--_dormant_max;
   362 	wake_was_empty = true;
   363       }
   364 
   365       int min_dist = std::numeric_limits<int>::max();
   366       for (typename WakeMap::TrueIt it(*_wake); it != INVALID; ++it) {
   367 	if (min_dist > (*_dist)[it]){
   368 	  _target = it;
   369 	  min_dist = (*_dist)[it];
   370 	}
   371       }
   372 
   373       if (wake_was_empty){
   374 	for (typename WakeMap::TrueIt it(*_wake); it != INVALID; ++it) {
   375           if (_tolerance.positive((*_excess)[it])) {
   376 	    if ((*_wake)[it] && it != _target) {
   377 	      _active_nodes[(*_dist)[it]].push_front(it);
   378             }
   379 	    if (_highest_active < (*_dist)[it]) {
   380 	      _highest_active = (*_dist)[it];		    
   381             }
   382 	  }
   383 	}
   384       }
   385 
   386       for (ResOutEdgeIt e(res_graph, old_target); e!=INVALID; ++e){
   387 	if (!(*_source_set)[res_graph.target(e)]) {
   388           Value delta = res_graph.rescap(e);
   389           if (!_tolerance.positive(delta)) continue;
   390           res_graph.augment(e, delta);
   391           (*_excess)[res_graph.source(e)] -= delta;
   392           Node a = res_graph.target(e);
   393           if (!_tolerance.positive((*_excess)[a]) && 
   394               (*_wake)[a] && a != _target) {
   395             _active_nodes[(*_dist)[a]].push_front(a);
   396             if (_highest_active < (*_dist)[a]) {
   397               _highest_active = (*_dist)[a];
   398             }
   399           }
   400           (*_excess)[a] += delta;
   401 	}
   402       }
   403       
   404       return true;
   405     }
   406     
   407     Node findActiveNode() {
   408       while (_highest_active > 0 && _active_nodes[_highest_active].empty()){ 
   409 	--_highest_active;
   410       }
   411       if( _highest_active > 0) {
   412        	Node n = _active_nodes[_highest_active].front();
   413 	_active_nodes[_highest_active].pop_front();
   414 	return n;
   415       } else {
   416 	return INVALID;
   417       }
   418     }
   419 
   420     template <typename ResGraph, typename EdgeMap>
   421     typename ResGraph::Edge findAdmissibleEdge(const Node& n, 
   422                                                ResGraph& res_graph, 
   423                                                EdgeMap& current_edge) {
   424       typedef typename ResGraph::Edge ResEdge;
   425       ResEdge e = current_edge[n];
   426       while (e != INVALID && 
   427              ((*_dist)[n] <= (*_dist)[res_graph.target(e)] || 
   428               !(*_wake)[res_graph.target(e)])) {
   429 	res_graph.nextOut(e);
   430       }
   431       if (e != INVALID) {
   432 	current_edge[n] = e;	
   433 	return e;
   434       } else {
   435 	return INVALID;
   436       }
   437     }
   438 
   439     Value cutValue(bool out) {
   440       Value value = 0;
   441       if (out) {
   442         for (typename WakeMap::TrueIt it(*_wake); it != INVALID; ++it) {
   443           for (InEdgeIt e(*_graph, it); e != INVALID; ++e) {
   444             if (!(*_wake)[_graph->source(e)]){
   445               value += (*_capacity)[e];
   446             }	
   447           }
   448         }
   449       } else {
   450         for (typename WakeMap::TrueIt it(*_wake); it != INVALID; ++it) {
   451           for (OutEdgeIt e(*_graph, it); e != INVALID; ++e) {
   452             if (!(*_wake)[_graph->target(e)]){
   453               value += (*_capacity)[e];
   454             }	
   455           }
   456         }
   457       }
   458       return value;
   459     }
   460 
   461 
   462   public:
   463 
   464     /// \name Execution control
   465     /// The simplest way to execute the algorithm is to use
   466     /// one of the member functions called \c run(...).
   467     /// \n
   468     /// If you need more control on the execution,
   469     /// first you must call \ref init(), then the \ref calculateIn() or
   470     /// \ref calculateIn() functions.
   471 
   472     /// @{
   473 
   474     /// \brief Initializes the internal data structures.
   475     ///
   476     /// Initializes the internal data structures. It creates
   477     /// the maps, residual graph adaptors and some bucket structures
   478     /// for the algorithm. 
   479     void init() {
   480       init(NodeIt(*_graph));
   481     }
   482 
   483     /// \brief Initializes the internal data structures.
   484     ///
   485     /// Initializes the internal data structures. It creates
   486     /// the maps, residual graph adaptor and some bucket structures
   487     /// for the algorithm. Node \c source  is used as the push-relabel
   488     /// algorithm's source.
   489     void init(const Node& source) {
   490       _source = source;
   491       _node_num = countNodes(*_graph);
   492 
   493       _dormant.resize(_node_num);
   494       _level_size.resize(_node_num, 0);
   495       _active_nodes.resize(_node_num);
   496 
   497       if (!_preflow) {
   498         _preflow = new FlowMap(*_graph);
   499       }
   500       if (!_wake) {
   501         _wake = new WakeMap(*_graph);
   502       }
   503       if (!_dist) {
   504         _dist = new DistMap(*_graph);
   505       }
   506       if (!_excess) {
   507         _excess = new ExcessMap(*_graph);
   508       }
   509       if (!_source_set) {
   510         _source_set = new SourceSetMap(*_graph);
   511       }
   512       if (!_out_res_graph) {
   513         _out_res_graph = new OutResGraph(*_graph, *_capacity, *_preflow);
   514       }
   515       if (!_out_current_edge) {
   516         _out_current_edge = new OutCurrentEdgeMap(*_graph);
   517       }
   518       if (!_rev_graph) {
   519         _rev_graph = new RevGraph(*_graph);
   520       }
   521       if (!_in_res_graph) {
   522         _in_res_graph = new InResGraph(*_rev_graph, *_capacity, *_preflow);
   523       }
   524       if (!_in_current_edge) {
   525         _in_current_edge = new InCurrentEdgeMap(*_graph);
   526       }
   527       if (!_min_cut_map) {
   528         _min_cut_map = new MinCutMap(*_graph);
   529       }
   530 
   531       _min_cut = std::numeric_limits<Value>::max();
   532     }
   533 
   534 
   535     /// \brief Calculates a minimum cut with \f$ source \f$ on the
   536     /// source-side.
   537     ///
   538     /// \brief Calculates a minimum cut with \f$ source \f$ on the
   539     /// source-side (i.e. a set \f$ X\subsetneq V \f$ with \f$ source \in X \f$
   540     ///  and minimal out-degree).
   541     void calculateOut() {
   542       for (NodeIt it(*_graph); it != INVALID; ++it) {
   543         if (it != _source) {
   544           calculateOut(it);
   545           return;
   546         }
   547       }
   548     }
   549 
   550     /// \brief Calculates a minimum cut with \f$ source \f$ on the
   551     /// source-side.
   552     ///
   553     /// \brief Calculates a minimum cut with \f$ source \f$ on the
   554     /// source-side (i.e. a set \f$ X\subsetneq V \f$ with \f$ source \in X \f$
   555     ///  and minimal out-degree). The \c target is the initial target
   556     /// for the push-relabel algorithm.
   557     void calculateOut(const Node& target) {
   558       findMinCut(target, true, *_out_res_graph, *_out_current_edge);
   559     }
   560 
   561     /// \brief Calculates a minimum cut with \f$ source \f$ on the
   562     /// sink-side.
   563     ///
   564     /// \brief Calculates a minimum cut with \f$ source \f$ on the
   565     /// sink-side (i.e. a set \f$ X\subsetneq V \f$ with 
   566     /// \f$ source \notin X \f$
   567     /// and minimal out-degree).
   568     void calculateIn() {
   569       for (NodeIt it(*_graph); it != INVALID; ++it) {
   570         if (it != _source) {
   571           calculateIn(it);
   572           return;
   573         }
   574       }
   575     }
   576 
   577     /// \brief Calculates a minimum cut with \f$ source \f$ on the
   578     /// sink-side.
   579     ///
   580     /// \brief Calculates a minimum cut with \f$ source \f$ on the
   581     /// sink-side (i.e. a set \f$ X\subsetneq V 
   582     /// \f$ with \f$ source \notin X \f$ and minimal out-degree).  
   583     /// The \c target is the initial
   584     /// target for the push-relabel algorithm.
   585     void calculateIn(const Node& target) {
   586       findMinCut(target, false, *_in_res_graph, *_in_current_edge);
   587     }
   588 
   589     /// \brief Runs the algorithm.
   590     ///
   591     /// Runs the algorithm. It finds nodes \c source and \c target
   592     /// arbitrarily and then calls \ref init(), \ref calculateOut()
   593     /// and \ref calculateIn().
   594     void run() {
   595       init();
   596       for (NodeIt it(*_graph); it != INVALID; ++it) {
   597         if (it != _source) {
   598           calculateOut(it);
   599           calculateIn(it);
   600           return;
   601         }
   602       }
   603     }
   604 
   605     /// \brief Runs the algorithm.
   606     ///
   607     /// Runs the algorithm. It uses the given \c source node, finds a
   608     /// proper \c target and then calls the \ref init(), \ref
   609     /// calculateOut() and \ref calculateIn().
   610     void run(const Node& s) {
   611       init(s);
   612       for (NodeIt it(*_graph); it != INVALID; ++it) {
   613         if (it != _source) {
   614           calculateOut(it);
   615           calculateIn(it);
   616           return;
   617         }
   618       }
   619     }
   620 
   621     /// \brief Runs the algorithm.
   622     ///
   623     /// Runs the algorithm. It just calls the \ref init() and then
   624     /// \ref calculateOut() and \ref calculateIn().
   625     void run(const Node& s, const Node& t) {
   626       init(s); 
   627       calculateOut(t);
   628       calculateIn(t);
   629     }
   630 
   631     /// @}
   632     
   633     /// \name Query Functions 
   634     /// The result of the %HaoOrlin algorithm
   635     /// can be obtained using these functions.
   636     /// \n
   637     /// Before using these functions, either \ref run(), \ref
   638     /// calculateOut() or \ref calculateIn() must be called.
   639     
   640     /// @{
   641 
   642     /// \brief Returns the value of the minimum value cut.
   643     /// 
   644     /// Returns the value of the minimum value cut.
   645     Value minCut() const {
   646       return _min_cut;
   647     }
   648 
   649 
   650     /// \brief Returns a minimum cut.
   651     ///
   652     /// Sets \c nodeMap to the characteristic vector of a minimum
   653     /// value cut: it will give a nonempty set \f$ X\subsetneq V \f$
   654     /// with minimal out-degree (i.e. \c nodeMap will be true exactly
   655     /// for the nodes of \f$ X \f$).  \pre nodeMap should be a
   656     /// bool-valued node-map.
   657     template <typename NodeMap>
   658     Value minCut(NodeMap& nodeMap) const {
   659       for (NodeIt it(*_graph); it != INVALID; ++it) {
   660 	nodeMap.set(it, (*_min_cut_map)[it]);
   661       }
   662       return minCut();
   663     }
   664 
   665     /// @}
   666     
   667   }; //class HaoOrlin 
   668 
   669 
   670 } //namespace lemon
   671 
   672 #endif //LEMON_HAO_ORLIN_H