lemon/gomory_hu_tree.h
author Janos Tapolcai <tapolcai@tmit.bme.hu>
Fri, 20 Feb 2009 17:17:17 +0100
changeset 590 924887566bf2
child 591 ccd2d3a3001e
permissions -rw-r--r--
Porting Gomory-Hu algorithm (#66)
tapolcai@590
     1
/* -*- C++ -*-
tapolcai@590
     2
 *
tapolcai@590
     3
 * This file is a part of LEMON, a generic C++ optimization library
tapolcai@590
     4
 *
tapolcai@590
     5
 * Copyright (C) 2003-2008
tapolcai@590
     6
 * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport
tapolcai@590
     7
 * (Egervary Research Group on Combinatorial Optimization, EGRES).
tapolcai@590
     8
 *
tapolcai@590
     9
 * Permission to use, modify and distribute this software is granted
tapolcai@590
    10
 * provided that this copyright notice appears in all copies. For
tapolcai@590
    11
 * precise terms see the accompanying LICENSE file.
tapolcai@590
    12
 *
tapolcai@590
    13
 * This software is provided "AS IS" with no warranty of any kind,
tapolcai@590
    14
 * express or implied, and with no claim as to its suitability for any
tapolcai@590
    15
 * purpose.
tapolcai@590
    16
 *
tapolcai@590
    17
 */
tapolcai@590
    18
tapolcai@590
    19
#ifndef LEMON_GOMORY_HU_TREE_H
tapolcai@590
    20
#define LEMON_GOMORY_HU_TREE_H
tapolcai@590
    21
tapolcai@590
    22
#include <limits>
tapolcai@590
    23
tapolcai@590
    24
#include <lemon/preflow.h>
tapolcai@590
    25
#include <lemon/concept_check.h>
tapolcai@590
    26
#include <lemon/concepts/maps.h>
tapolcai@590
    27
tapolcai@590
    28
/// \ingroup min_cut
tapolcai@590
    29
/// \file 
tapolcai@590
    30
/// \brief Gomory-Hu cut tree in graphs.
tapolcai@590
    31
tapolcai@590
    32
namespace lemon {
tapolcai@590
    33
tapolcai@590
    34
  /// \ingroup min_cut
tapolcai@590
    35
  ///
tapolcai@590
    36
  /// \brief Gomory-Hu cut tree algorithm
tapolcai@590
    37
  ///
tapolcai@590
    38
  /// The Gomory-Hu tree is a tree on the nodeset of the digraph, but it
tapolcai@590
    39
  /// may contain arcs which are not in the original digraph. It helps
tapolcai@590
    40
  /// to calculate the minimum cut between all pairs of nodes, because
tapolcai@590
    41
  /// the minimum capacity arc on the tree path between two nodes has
tapolcai@590
    42
  /// the same weight as the minimum cut in the digraph between these
tapolcai@590
    43
  /// nodes. Moreover this arc separates the nodes to two parts which
tapolcai@590
    44
  /// determine this minimum cut.
tapolcai@590
    45
  /// 
tapolcai@590
    46
  /// The algorithm calculates \e n-1 distinict minimum cuts with
tapolcai@590
    47
  /// preflow algorithm, therefore the algorithm has
tapolcai@590
    48
  /// \f$(O(n^3\sqrt{e})\f$ overall time complexity. It calculates a
tapolcai@590
    49
  /// rooted Gomory-Hu tree, the structure of the tree and the weights
tapolcai@590
    50
  /// can be obtained with \c predNode() and \c predValue()
tapolcai@590
    51
  /// functions. The \c minCutValue() and \c minCutMap() calculates
tapolcai@590
    52
  /// the minimum cut and the minimum cut value between any two node
tapolcai@590
    53
  /// in the digraph.
tapolcai@590
    54
  template <typename _Graph, 
tapolcai@590
    55
	    typename _Capacity = typename _Graph::template EdgeMap<int> >
tapolcai@590
    56
  class GomoryHuTree {
tapolcai@590
    57
  public:
tapolcai@590
    58
tapolcai@590
    59
    /// The graph type
tapolcai@590
    60
    typedef _Graph Graph;
tapolcai@590
    61
    /// The capacity on edges
tapolcai@590
    62
    typedef _Capacity Capacity;
tapolcai@590
    63
    /// The value type of capacities
tapolcai@590
    64
    typedef typename Capacity::Value Value;
tapolcai@590
    65
    
tapolcai@590
    66
  private:
tapolcai@590
    67
tapolcai@590
    68
    TEMPLATE_GRAPH_TYPEDEFS(Graph);
tapolcai@590
    69
tapolcai@590
    70
    const Graph& _graph;
tapolcai@590
    71
    const Capacity& _capacity;
tapolcai@590
    72
tapolcai@590
    73
    Node _root;
tapolcai@590
    74
    typename Graph::template NodeMap<Node>* _pred;
tapolcai@590
    75
    typename Graph::template NodeMap<Value>* _weight;
tapolcai@590
    76
    typename Graph::template NodeMap<int>* _order;
tapolcai@590
    77
tapolcai@590
    78
    void createStructures() {
tapolcai@590
    79
      if (!_pred) {
tapolcai@590
    80
	_pred = new typename Graph::template NodeMap<Node>(_graph);
tapolcai@590
    81
      }
tapolcai@590
    82
      if (!_weight) {
tapolcai@590
    83
	_weight = new typename Graph::template NodeMap<Value>(_graph);
tapolcai@590
    84
      }
tapolcai@590
    85
      if (!_order) {
tapolcai@590
    86
	_order = new typename Graph::template NodeMap<int>(_graph);
tapolcai@590
    87
      }
tapolcai@590
    88
    }
tapolcai@590
    89
tapolcai@590
    90
    void destroyStructures() {
tapolcai@590
    91
      if (_pred) {
tapolcai@590
    92
	delete _pred;
tapolcai@590
    93
      }
tapolcai@590
    94
      if (_weight) {
tapolcai@590
    95
	delete _weight;
tapolcai@590
    96
      }
tapolcai@590
    97
      if (_order) {
tapolcai@590
    98
	delete _order;
tapolcai@590
    99
      }
tapolcai@590
   100
    }
tapolcai@590
   101
  
tapolcai@590
   102
  public:
tapolcai@590
   103
tapolcai@590
   104
    /// \brief Constructor
tapolcai@590
   105
    ///
tapolcai@590
   106
    /// Constructor
tapolcai@590
   107
    /// \param graph The graph type.
tapolcai@590
   108
    /// \param capacity The capacity map.
tapolcai@590
   109
    GomoryHuTree(const Graph& graph, const Capacity& capacity) 
tapolcai@590
   110
      : _graph(graph), _capacity(capacity),
tapolcai@590
   111
	_pred(0), _weight(0), _order(0) 
tapolcai@590
   112
    {
tapolcai@590
   113
      checkConcept<concepts::ReadMap<Edge, Value>, Capacity>();
tapolcai@590
   114
    }
tapolcai@590
   115
tapolcai@590
   116
tapolcai@590
   117
    /// \brief Destructor
tapolcai@590
   118
    ///
tapolcai@590
   119
    /// Destructor
tapolcai@590
   120
    ~GomoryHuTree() {
tapolcai@590
   121
      destroyStructures();
tapolcai@590
   122
    }
tapolcai@590
   123
tapolcai@590
   124
    /// \brief Initializes the internal data structures.
tapolcai@590
   125
    ///
tapolcai@590
   126
    /// Initializes the internal data structures.
tapolcai@590
   127
    ///
tapolcai@590
   128
    void init() {
tapolcai@590
   129
      createStructures();
tapolcai@590
   130
tapolcai@590
   131
      _root = NodeIt(_graph);
tapolcai@590
   132
      for (NodeIt n(_graph); n != INVALID; ++n) {
tapolcai@590
   133
	_pred->set(n, _root);
tapolcai@590
   134
	_order->set(n, -1);
tapolcai@590
   135
      }
tapolcai@590
   136
      _pred->set(_root, INVALID);
tapolcai@590
   137
      _weight->set(_root, std::numeric_limits<Value>::max()); 
tapolcai@590
   138
    }
tapolcai@590
   139
tapolcai@590
   140
tapolcai@590
   141
    /// \brief Starts the algorithm
tapolcai@590
   142
    ///
tapolcai@590
   143
    /// Starts the algorithm.
tapolcai@590
   144
    void start() {
tapolcai@590
   145
      Preflow<Graph, Capacity> fa(_graph, _capacity, _root, INVALID);
tapolcai@590
   146
tapolcai@590
   147
      for (NodeIt n(_graph); n != INVALID; ++n) {
tapolcai@590
   148
	if (n == _root) continue;
tapolcai@590
   149
tapolcai@590
   150
	Node pn = (*_pred)[n];
tapolcai@590
   151
	fa.source(n);
tapolcai@590
   152
	fa.target(pn);
tapolcai@590
   153
tapolcai@590
   154
	fa.runMinCut();
tapolcai@590
   155
tapolcai@590
   156
	_weight->set(n, fa.flowValue());
tapolcai@590
   157
tapolcai@590
   158
	for (NodeIt nn(_graph); nn != INVALID; ++nn) {
tapolcai@590
   159
	  if (nn != n && fa.minCut(nn) && (*_pred)[nn] == pn) {
tapolcai@590
   160
	    _pred->set(nn, n);
tapolcai@590
   161
	  }
tapolcai@590
   162
	}
tapolcai@590
   163
	if ((*_pred)[pn] != INVALID && fa.minCut((*_pred)[pn])) {
tapolcai@590
   164
	  _pred->set(n, (*_pred)[pn]);
tapolcai@590
   165
	  _pred->set(pn, n);
tapolcai@590
   166
	  _weight->set(n, (*_weight)[pn]);
tapolcai@590
   167
	  _weight->set(pn, fa.flowValue());	
tapolcai@590
   168
	}
tapolcai@590
   169
      }
tapolcai@590
   170
tapolcai@590
   171
      _order->set(_root, 0);
tapolcai@590
   172
      int index = 1;
tapolcai@590
   173
tapolcai@590
   174
      for (NodeIt n(_graph); n != INVALID; ++n) {
tapolcai@590
   175
	std::vector<Node> st;
tapolcai@590
   176
	Node nn = n;
tapolcai@590
   177
	while ((*_order)[nn] == -1) {
tapolcai@590
   178
	  st.push_back(nn);
tapolcai@590
   179
	  nn = (*_pred)[nn];
tapolcai@590
   180
	}
tapolcai@590
   181
	while (!st.empty()) {
tapolcai@590
   182
	  _order->set(st.back(), index++);
tapolcai@590
   183
	  st.pop_back();
tapolcai@590
   184
	}
tapolcai@590
   185
      }
tapolcai@590
   186
    }
tapolcai@590
   187
tapolcai@590
   188
    /// \brief Runs the Gomory-Hu algorithm.  
tapolcai@590
   189
    ///
tapolcai@590
   190
    /// Runs the Gomory-Hu algorithm.
tapolcai@590
   191
    /// \note gh.run() is just a shortcut of the following code.
tapolcai@590
   192
    /// \code
tapolcai@590
   193
    ///   ght.init();
tapolcai@590
   194
    ///   ght.start();
tapolcai@590
   195
    /// \endcode
tapolcai@590
   196
    void run() {
tapolcai@590
   197
      init();
tapolcai@590
   198
      start();
tapolcai@590
   199
    }
tapolcai@590
   200
tapolcai@590
   201
    /// \brief Returns the predecessor node in the Gomory-Hu tree.
tapolcai@590
   202
    ///
tapolcai@590
   203
    /// Returns the predecessor node in the Gomory-Hu tree. If the node is
tapolcai@590
   204
    /// the root of the Gomory-Hu tree, then it returns \c INVALID.
tapolcai@590
   205
    Node predNode(const Node& node) {
tapolcai@590
   206
      return (*_pred)[node];
tapolcai@590
   207
    }
tapolcai@590
   208
tapolcai@590
   209
    /// \brief Returns the weight of the predecessor arc in the
tapolcai@590
   210
    /// Gomory-Hu tree.
tapolcai@590
   211
    ///
tapolcai@590
   212
    /// Returns the weight of the predecessor arc in the Gomory-Hu
tapolcai@590
   213
    /// tree.  If the node is the root of the Gomory-Hu tree, the
tapolcai@590
   214
    /// result is undefined.
tapolcai@590
   215
    Value predValue(const Node& node) {
tapolcai@590
   216
      return (*_weight)[node];
tapolcai@590
   217
    }
tapolcai@590
   218
tapolcai@590
   219
    /// \brief Returns the minimum cut value between two nodes
tapolcai@590
   220
    ///
tapolcai@590
   221
    /// Returns the minimum cut value between two nodes. The
tapolcai@590
   222
    /// algorithm finds the nearest common ancestor in the Gomory-Hu
tapolcai@590
   223
    /// tree and calculates the minimum weight arc on the paths to
tapolcai@590
   224
    /// the ancestor.
tapolcai@590
   225
    Value minCutValue(const Node& s, const Node& t) const {
tapolcai@590
   226
      Node sn = s, tn = t;
tapolcai@590
   227
      Value value = std::numeric_limits<Value>::max();
tapolcai@590
   228
      
tapolcai@590
   229
      while (sn != tn) {
tapolcai@590
   230
	if ((*_order)[sn] < (*_order)[tn]) {
tapolcai@590
   231
	  if ((*_weight)[tn] < value) value = (*_weight)[tn];
tapolcai@590
   232
	  tn = (*_pred)[tn];
tapolcai@590
   233
	} else {
tapolcai@590
   234
	  if ((*_weight)[sn] < value) value = (*_weight)[sn];
tapolcai@590
   235
	  sn = (*_pred)[sn];
tapolcai@590
   236
	}
tapolcai@590
   237
      }
tapolcai@590
   238
      return value;
tapolcai@590
   239
    }
tapolcai@590
   240
tapolcai@590
   241
    /// \brief Returns the minimum cut between two nodes
tapolcai@590
   242
    ///
tapolcai@590
   243
    /// Returns the minimum cut value between two nodes. The
tapolcai@590
   244
    /// algorithm finds the nearest common ancestor in the Gomory-Hu
tapolcai@590
   245
    /// tree and calculates the minimum weight arc on the paths to
tapolcai@590
   246
    /// the ancestor. Then it sets all nodes to the cut determined by
tapolcai@590
   247
    /// this arc. The \c cutMap should be \ref concepts::ReadWriteMap
tapolcai@590
   248
    /// "ReadWriteMap".
tapolcai@590
   249
    template <typename CutMap>
tapolcai@590
   250
    Value minCutMap(const Node& s, const Node& t, CutMap& cutMap) const {
tapolcai@590
   251
      Node sn = s, tn = t;
tapolcai@590
   252
tapolcai@590
   253
      Node rn = INVALID;
tapolcai@590
   254
      Value value = std::numeric_limits<Value>::max();
tapolcai@590
   255
      
tapolcai@590
   256
      while (sn != tn) {
tapolcai@590
   257
	if ((*_order)[sn] < (*_order)[tn]) {
tapolcai@590
   258
	  if ((*_weight)[tn] < value) {
tapolcai@590
   259
	    rn = tn;
tapolcai@590
   260
	    value = (*_weight)[tn];
tapolcai@590
   261
	  }
tapolcai@590
   262
	  tn = (*_pred)[tn];
tapolcai@590
   263
	} else {
tapolcai@590
   264
	  if ((*_weight)[sn] < value) {
tapolcai@590
   265
	    rn = sn;
tapolcai@590
   266
	    value = (*_weight)[sn];
tapolcai@590
   267
	  }
tapolcai@590
   268
	  sn = (*_pred)[sn];
tapolcai@590
   269
	}
tapolcai@590
   270
      }
tapolcai@590
   271
tapolcai@590
   272
      typename Graph::template NodeMap<bool> reached(_graph, false);
tapolcai@590
   273
      reached.set(_root, true);
tapolcai@590
   274
      cutMap.set(_root, false);
tapolcai@590
   275
      reached.set(rn, true);
tapolcai@590
   276
      cutMap.set(rn, true);
tapolcai@590
   277
tapolcai@590
   278
      for (NodeIt n(_graph); n != INVALID; ++n) {
tapolcai@590
   279
	std::vector<Node> st;
tapolcai@590
   280
	Node nn = n;
tapolcai@590
   281
	while (!reached[nn]) {
tapolcai@590
   282
	  st.push_back(nn);
tapolcai@590
   283
	  nn = (*_pred)[nn];
tapolcai@590
   284
	}
tapolcai@590
   285
	while (!st.empty()) {
tapolcai@590
   286
	  cutMap.set(st.back(), cutMap[nn]);
tapolcai@590
   287
	  st.pop_back();
tapolcai@590
   288
	}
tapolcai@590
   289
      }
tapolcai@590
   290
      
tapolcai@590
   291
      return value;
tapolcai@590
   292
    }
tapolcai@590
   293
tapolcai@590
   294
  };
tapolcai@590
   295
tapolcai@590
   296
}
tapolcai@590
   297
tapolcai@590
   298
#endif