lemon/steiner.h
changeset 2382 678bea23ed75
child 2386 81b47fc5c444
equal deleted inserted replaced
-1:000000000000 0:4dd4e8430dae
       
     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_STEINER_H
       
    20 #define LEMON_STEINER_H
       
    21 
       
    22 ///\ingroup approx
       
    23 ///\file
       
    24 ///\brief Algorithm for the 2-approximation of Steiner Tree problem.
       
    25 ///
       
    26 
       
    27 #include <lemon/smart_graph.h>
       
    28 #include <lemon/graph_utils.h>
       
    29 #include <lemon/error.h>
       
    30 
       
    31 #include <lemon/ugraph_adaptor.h>
       
    32 #include <lemon/maps.h>
       
    33 
       
    34 #include <lemon/dijkstra.h>
       
    35 #include <lemon/prim.h>
       
    36 
       
    37 
       
    38 namespace lemon {
       
    39 
       
    40   /// \ingroup approx
       
    41   
       
    42   /// \brief Algorithm for the 2-approximation of Steiner Tree problem
       
    43   ///
       
    44   /// The Steiner-tree problem is the next: Given a connected
       
    45   /// undirected graph, a cost function on the edges and a subset of
       
    46   /// the nodes. Construct a tree with minimum cost which covers the
       
    47   /// given subset of the nodes. The problem is NP-hard moreover
       
    48   /// it is APX-complete too.
       
    49   ///
       
    50   /// Mehlhorn's approximation algorithm is implemented in this class,
       
    51   /// which gives a 2-approximation for the Steiner-tree problem. The
       
    52   /// algorithm's time complexity is O(nlog(n)+e).
       
    53   template <typename UGraph,
       
    54             typename CostMap = typename UGraph:: template UEdgeMap<double> >
       
    55   class SteinerTree {
       
    56   public:
       
    57     
       
    58     UGRAPH_TYPEDEFS(typename UGraph)
       
    59 
       
    60     typedef typename CostMap::Value Value;
       
    61     
       
    62   private:
       
    63 
       
    64     class CompMap {
       
    65     public:
       
    66       typedef Node Key;
       
    67       typedef Edge Value;
       
    68 
       
    69     private:
       
    70       const UGraph& _graph;
       
    71       typename UGraph::template NodeMap<int> _comp;
       
    72 
       
    73     public:
       
    74       CompMap(const UGraph& graph) : _graph(graph), _comp(graph) {}
       
    75 
       
    76       void set(const Node& node, const Edge& edge) {
       
    77         if (edge != INVALID) {
       
    78           _comp.set(node, _comp[_graph.source(edge)]);
       
    79         } else {
       
    80           _comp.set(node, -1);
       
    81         }
       
    82       }
       
    83 
       
    84       int comp(const Node& node) const { return _comp[node]; }
       
    85       void comp(const Node& node, int value) { _comp.set(node, value); }
       
    86     };
       
    87 
       
    88     typedef typename UGraph::template NodeMap<Edge> PredMap;
       
    89 
       
    90     typedef ForkWriteMap<PredMap, CompMap> ForkedMap;
       
    91 
       
    92 
       
    93     struct External {
       
    94       int source, target;
       
    95       UEdge uedge;
       
    96       Value value;
       
    97 
       
    98       External(int s, int t, const UEdge& e, const Value& v)
       
    99         : source(s), target(t), uedge(e), value(v) {}
       
   100     };
       
   101 
       
   102     struct ExternalLess {
       
   103       bool operator()(const External& left, const External& right) const {
       
   104         return (left.source < right.source) || 
       
   105           (left.source == right.source && left.target < right.target);
       
   106       }
       
   107     };
       
   108 
       
   109 
       
   110     typedef typename UGraph::template NodeMap<bool> FilterMap;
       
   111 
       
   112     typedef typename UGraph::template UEdgeMap<bool> TreeMap;
       
   113 
       
   114     const UGraph& _graph;
       
   115     const CostMap& _cost;
       
   116 
       
   117     typename Dijkstra<UGraph, CostMap>::
       
   118     template DefPredMap<ForkedMap>::Create _dijkstra;
       
   119 
       
   120     PredMap* _pred;
       
   121     CompMap* _comp;
       
   122     ForkedMap* _forked;
       
   123 
       
   124     int _terminal_num;
       
   125 
       
   126     FilterMap *_filter;
       
   127     TreeMap *_tree;
       
   128 
       
   129   public:
       
   130 
       
   131     /// \brief Constructor
       
   132     
       
   133     /// Constructor
       
   134     ///
       
   135     SteinerTree(const UGraph &graph, const CostMap &cost)
       
   136       : _graph(graph), _cost(cost), _dijkstra(graph, _cost), 
       
   137         _pred(0), _comp(0), _forked(0), _filter(0), _tree(0) {}
       
   138 
       
   139     /// \brief Initializes the internal data structures.
       
   140     ///
       
   141     /// Initializes the internal data structures.
       
   142     void init() {
       
   143       if (!_pred) _pred = new PredMap(_graph);
       
   144       if (!_comp) _comp = new CompMap(_graph);
       
   145       if (!_forked) _forked = new ForkedMap(*_pred, *_comp);
       
   146       if (!_filter) _filter = new FilterMap(_graph);
       
   147       if (!_tree) _tree = new TreeMap(_graph);
       
   148       _dijkstra.predMap(*_forked);
       
   149       _dijkstra.init();
       
   150       _terminal_num = 0;
       
   151       for (NodeIt it(_graph); it != INVALID; ++it) {
       
   152         _filter->set(it, false);
       
   153       }
       
   154     }
       
   155 
       
   156     /// \brief Adds a new terminal node.
       
   157     ///
       
   158     /// Adds a new terminal node to the Steiner-tree problem.
       
   159     void addTerminal(const Node& node) {
       
   160       if (!_dijkstra.reached(node)) {
       
   161         _dijkstra.addSource(node);
       
   162         _comp->comp(node, _terminal_num);
       
   163         ++_terminal_num;
       
   164       }
       
   165     }
       
   166     
       
   167     /// \brief Executes the algorithm.
       
   168     ///
       
   169     /// Executes the algorithm.
       
   170     ///
       
   171     /// \pre init() must be called and at least some nodes should be
       
   172     /// added with addTerminal() before using this function.
       
   173     ///
       
   174     /// This method constructs an approximation of the Steiner-Tree.
       
   175     void start() {
       
   176       _dijkstra.start();
       
   177       
       
   178       std::vector<External> externals;
       
   179       for (UEdgeIt it(_graph); it != INVALID; ++it) {
       
   180         Node s = _graph.source(it);
       
   181         Node t = _graph.target(it);
       
   182         if (_comp->comp(s) == _comp->comp(t)) continue;
       
   183 
       
   184         Value cost = _dijkstra.dist(s) + _dijkstra.dist(t) + _cost[it];
       
   185 
       
   186         if (_comp->comp(s) < _comp->comp(t)) {
       
   187           externals.push_back(External(_comp->comp(s), _comp->comp(t), 
       
   188                                        it, cost));
       
   189         } else {
       
   190           externals.push_back(External(_comp->comp(t), _comp->comp(s), 
       
   191                                        it, cost));
       
   192         }
       
   193       }
       
   194       std::sort(externals.begin(), externals.end(), ExternalLess());
       
   195 
       
   196       SmartUGraph aux_graph;
       
   197       std::vector<SmartUGraph::Node> aux_nodes;
       
   198 
       
   199       for (int i = 0; i < _terminal_num; ++i) {
       
   200         aux_nodes.push_back(aux_graph.addNode());
       
   201       }
       
   202 
       
   203       SmartUGraph::UEdgeMap<Value> aux_cost(aux_graph);
       
   204       SmartUGraph::UEdgeMap<UEdge> cross(aux_graph);
       
   205       {
       
   206         int i = 0;
       
   207         while (i < (int)externals.size()) {
       
   208           int sn = externals[i].source;
       
   209           int tn = externals[i].target;
       
   210           Value ev = externals[i].value;
       
   211           UEdge ee = externals[i].uedge;
       
   212           ++i;
       
   213           while (i < (int)externals.size() && 
       
   214                  sn == externals[i].source && tn == externals[i].target) {
       
   215             if (externals[i].value < ev) {
       
   216               ev = externals[i].value;
       
   217               ee = externals[i].uedge;
       
   218             }
       
   219             ++i;
       
   220           }
       
   221           SmartUGraph::UEdge ne = 
       
   222             aux_graph.addEdge(aux_nodes[sn], aux_nodes[tn]);
       
   223           aux_cost.set(ne, ev);
       
   224           cross.set(ne, ee);
       
   225         }
       
   226       }
       
   227 
       
   228       std::vector<SmartUGraph::UEdge> aux_tree_edges;
       
   229       BackInserterBoolMap<std::vector<SmartUGraph::UEdge> >
       
   230         aux_tree_map(aux_tree_edges);
       
   231       prim(aux_graph, aux_cost, aux_tree_map);
       
   232 
       
   233       for (std::vector<SmartUGraph::UEdge>::iterator 
       
   234              it = aux_tree_edges.begin(); it != aux_tree_edges.end(); ++it) {
       
   235         Node node;
       
   236         node = _graph.source(cross[*it]);
       
   237         while (node != INVALID && !(*_filter)[node]) {
       
   238           _filter->set(node, true);
       
   239           node = (*_pred)[node] != INVALID ? 
       
   240             _graph.source((*_pred)[node]) : INVALID;
       
   241         }
       
   242         node = _graph.target(cross[*it]);
       
   243         while (node != INVALID && !(*_filter)[node]) {
       
   244           _filter->set(node, true);
       
   245           node = (*_pred)[node] != INVALID ? 
       
   246             _graph.source((*_pred)[node]) : INVALID;
       
   247         }
       
   248       }
       
   249 
       
   250       prim(nodeSubUGraphAdaptor(_graph, *_filter), _cost, *_tree);
       
   251             
       
   252     }
       
   253 
       
   254     /// \brief Checks if an edge is in the Steiner-tree or not.
       
   255     ///
       
   256     /// Checks if an edge is in the Steiner-tree or not.
       
   257     /// \param e is the edge that will be checked
       
   258     /// \return \c true if e is in the Steiner-tree, \c false otherwise
       
   259     bool tree(UEdge e){
       
   260       return (*_tree)[e];
       
   261     }
       
   262 
       
   263     /// \brief Checks if the node is in the Steiner-tree or not.
       
   264     ///
       
   265     /// Checks if a node is in the Steiner-tree or not.
       
   266     /// \param n is the node that will be checked
       
   267     /// \return \c true if n is in the Steiner-tree, \c false otherwise
       
   268     bool tree(Node n){
       
   269       return (*_filter)[n];
       
   270     }
       
   271     
       
   272 
       
   273   };
       
   274 
       
   275 } //END OF NAMESPACE LEMON
       
   276 
       
   277 #endif