2-approximation of Steiner-tree problem
authordeba
Thu, 01 Mar 2007 16:47:49 +0000
changeset 2382678bea23ed75
parent 2381 0248790c66ea
child 2383 545926902c13
2-approximation of Steiner-tree problem
lemon/steiner.h
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/lemon/steiner.h	Thu Mar 01 16:47:49 2007 +0000
     1.3 @@ -0,0 +1,277 @@
     1.4 +/* -*- C++ -*-
     1.5 + *
     1.6 + * This file is a part of LEMON, a generic C++ optimization library
     1.7 + *
     1.8 + * Copyright (C) 2003-2006
     1.9 + * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport
    1.10 + * (Egervary Research Group on Combinatorial Optimization, EGRES).
    1.11 + *
    1.12 + * Permission to use, modify and distribute this software is granted
    1.13 + * provided that this copyright notice appears in all copies. For
    1.14 + * precise terms see the accompanying LICENSE file.
    1.15 + *
    1.16 + * This software is provided "AS IS" with no warranty of any kind,
    1.17 + * express or implied, and with no claim as to its suitability for any
    1.18 + * purpose.
    1.19 + *
    1.20 + */
    1.21 +
    1.22 +#ifndef LEMON_STEINER_H
    1.23 +#define LEMON_STEINER_H
    1.24 +
    1.25 +///\ingroup approx
    1.26 +///\file
    1.27 +///\brief Algorithm for the 2-approximation of Steiner Tree problem.
    1.28 +///
    1.29 +
    1.30 +#include <lemon/smart_graph.h>
    1.31 +#include <lemon/graph_utils.h>
    1.32 +#include <lemon/error.h>
    1.33 +
    1.34 +#include <lemon/ugraph_adaptor.h>
    1.35 +#include <lemon/maps.h>
    1.36 +
    1.37 +#include <lemon/dijkstra.h>
    1.38 +#include <lemon/prim.h>
    1.39 +
    1.40 +
    1.41 +namespace lemon {
    1.42 +
    1.43 +  /// \ingroup approx
    1.44 +  
    1.45 +  /// \brief Algorithm for the 2-approximation of Steiner Tree problem
    1.46 +  ///
    1.47 +  /// The Steiner-tree problem is the next: Given a connected
    1.48 +  /// undirected graph, a cost function on the edges and a subset of
    1.49 +  /// the nodes. Construct a tree with minimum cost which covers the
    1.50 +  /// given subset of the nodes. The problem is NP-hard moreover
    1.51 +  /// it is APX-complete too.
    1.52 +  ///
    1.53 +  /// Mehlhorn's approximation algorithm is implemented in this class,
    1.54 +  /// which gives a 2-approximation for the Steiner-tree problem. The
    1.55 +  /// algorithm's time complexity is O(nlog(n)+e).
    1.56 +  template <typename UGraph,
    1.57 +            typename CostMap = typename UGraph:: template UEdgeMap<double> >
    1.58 +  class SteinerTree {
    1.59 +  public:
    1.60 +    
    1.61 +    UGRAPH_TYPEDEFS(typename UGraph)
    1.62 +
    1.63 +    typedef typename CostMap::Value Value;
    1.64 +    
    1.65 +  private:
    1.66 +
    1.67 +    class CompMap {
    1.68 +    public:
    1.69 +      typedef Node Key;
    1.70 +      typedef Edge Value;
    1.71 +
    1.72 +    private:
    1.73 +      const UGraph& _graph;
    1.74 +      typename UGraph::template NodeMap<int> _comp;
    1.75 +
    1.76 +    public:
    1.77 +      CompMap(const UGraph& graph) : _graph(graph), _comp(graph) {}
    1.78 +
    1.79 +      void set(const Node& node, const Edge& edge) {
    1.80 +        if (edge != INVALID) {
    1.81 +          _comp.set(node, _comp[_graph.source(edge)]);
    1.82 +        } else {
    1.83 +          _comp.set(node, -1);
    1.84 +        }
    1.85 +      }
    1.86 +
    1.87 +      int comp(const Node& node) const { return _comp[node]; }
    1.88 +      void comp(const Node& node, int value) { _comp.set(node, value); }
    1.89 +    };
    1.90 +
    1.91 +    typedef typename UGraph::template NodeMap<Edge> PredMap;
    1.92 +
    1.93 +    typedef ForkWriteMap<PredMap, CompMap> ForkedMap;
    1.94 +
    1.95 +
    1.96 +    struct External {
    1.97 +      int source, target;
    1.98 +      UEdge uedge;
    1.99 +      Value value;
   1.100 +
   1.101 +      External(int s, int t, const UEdge& e, const Value& v)
   1.102 +        : source(s), target(t), uedge(e), value(v) {}
   1.103 +    };
   1.104 +
   1.105 +    struct ExternalLess {
   1.106 +      bool operator()(const External& left, const External& right) const {
   1.107 +        return (left.source < right.source) || 
   1.108 +          (left.source == right.source && left.target < right.target);
   1.109 +      }
   1.110 +    };
   1.111 +
   1.112 +
   1.113 +    typedef typename UGraph::template NodeMap<bool> FilterMap;
   1.114 +
   1.115 +    typedef typename UGraph::template UEdgeMap<bool> TreeMap;
   1.116 +
   1.117 +    const UGraph& _graph;
   1.118 +    const CostMap& _cost;
   1.119 +
   1.120 +    typename Dijkstra<UGraph, CostMap>::
   1.121 +    template DefPredMap<ForkedMap>::Create _dijkstra;
   1.122 +
   1.123 +    PredMap* _pred;
   1.124 +    CompMap* _comp;
   1.125 +    ForkedMap* _forked;
   1.126 +
   1.127 +    int _terminal_num;
   1.128 +
   1.129 +    FilterMap *_filter;
   1.130 +    TreeMap *_tree;
   1.131 +
   1.132 +  public:
   1.133 +
   1.134 +    /// \brief Constructor
   1.135 +    
   1.136 +    /// Constructor
   1.137 +    ///
   1.138 +    SteinerTree(const UGraph &graph, const CostMap &cost)
   1.139 +      : _graph(graph), _cost(cost), _dijkstra(graph, _cost), 
   1.140 +        _pred(0), _comp(0), _forked(0), _filter(0), _tree(0) {}
   1.141 +
   1.142 +    /// \brief Initializes the internal data structures.
   1.143 +    ///
   1.144 +    /// Initializes the internal data structures.
   1.145 +    void init() {
   1.146 +      if (!_pred) _pred = new PredMap(_graph);
   1.147 +      if (!_comp) _comp = new CompMap(_graph);
   1.148 +      if (!_forked) _forked = new ForkedMap(*_pred, *_comp);
   1.149 +      if (!_filter) _filter = new FilterMap(_graph);
   1.150 +      if (!_tree) _tree = new TreeMap(_graph);
   1.151 +      _dijkstra.predMap(*_forked);
   1.152 +      _dijkstra.init();
   1.153 +      _terminal_num = 0;
   1.154 +      for (NodeIt it(_graph); it != INVALID; ++it) {
   1.155 +        _filter->set(it, false);
   1.156 +      }
   1.157 +    }
   1.158 +
   1.159 +    /// \brief Adds a new terminal node.
   1.160 +    ///
   1.161 +    /// Adds a new terminal node to the Steiner-tree problem.
   1.162 +    void addTerminal(const Node& node) {
   1.163 +      if (!_dijkstra.reached(node)) {
   1.164 +        _dijkstra.addSource(node);
   1.165 +        _comp->comp(node, _terminal_num);
   1.166 +        ++_terminal_num;
   1.167 +      }
   1.168 +    }
   1.169 +    
   1.170 +    /// \brief Executes the algorithm.
   1.171 +    ///
   1.172 +    /// Executes the algorithm.
   1.173 +    ///
   1.174 +    /// \pre init() must be called and at least some nodes should be
   1.175 +    /// added with addTerminal() before using this function.
   1.176 +    ///
   1.177 +    /// This method constructs an approximation of the Steiner-Tree.
   1.178 +    void start() {
   1.179 +      _dijkstra.start();
   1.180 +      
   1.181 +      std::vector<External> externals;
   1.182 +      for (UEdgeIt it(_graph); it != INVALID; ++it) {
   1.183 +        Node s = _graph.source(it);
   1.184 +        Node t = _graph.target(it);
   1.185 +        if (_comp->comp(s) == _comp->comp(t)) continue;
   1.186 +
   1.187 +        Value cost = _dijkstra.dist(s) + _dijkstra.dist(t) + _cost[it];
   1.188 +
   1.189 +        if (_comp->comp(s) < _comp->comp(t)) {
   1.190 +          externals.push_back(External(_comp->comp(s), _comp->comp(t), 
   1.191 +                                       it, cost));
   1.192 +        } else {
   1.193 +          externals.push_back(External(_comp->comp(t), _comp->comp(s), 
   1.194 +                                       it, cost));
   1.195 +        }
   1.196 +      }
   1.197 +      std::sort(externals.begin(), externals.end(), ExternalLess());
   1.198 +
   1.199 +      SmartUGraph aux_graph;
   1.200 +      std::vector<SmartUGraph::Node> aux_nodes;
   1.201 +
   1.202 +      for (int i = 0; i < _terminal_num; ++i) {
   1.203 +        aux_nodes.push_back(aux_graph.addNode());
   1.204 +      }
   1.205 +
   1.206 +      SmartUGraph::UEdgeMap<Value> aux_cost(aux_graph);
   1.207 +      SmartUGraph::UEdgeMap<UEdge> cross(aux_graph);
   1.208 +      {
   1.209 +        int i = 0;
   1.210 +        while (i < (int)externals.size()) {
   1.211 +          int sn = externals[i].source;
   1.212 +          int tn = externals[i].target;
   1.213 +          Value ev = externals[i].value;
   1.214 +          UEdge ee = externals[i].uedge;
   1.215 +          ++i;
   1.216 +          while (i < (int)externals.size() && 
   1.217 +                 sn == externals[i].source && tn == externals[i].target) {
   1.218 +            if (externals[i].value < ev) {
   1.219 +              ev = externals[i].value;
   1.220 +              ee = externals[i].uedge;
   1.221 +            }
   1.222 +            ++i;
   1.223 +          }
   1.224 +          SmartUGraph::UEdge ne = 
   1.225 +            aux_graph.addEdge(aux_nodes[sn], aux_nodes[tn]);
   1.226 +          aux_cost.set(ne, ev);
   1.227 +          cross.set(ne, ee);
   1.228 +        }
   1.229 +      }
   1.230 +
   1.231 +      std::vector<SmartUGraph::UEdge> aux_tree_edges;
   1.232 +      BackInserterBoolMap<std::vector<SmartUGraph::UEdge> >
   1.233 +        aux_tree_map(aux_tree_edges);
   1.234 +      prim(aux_graph, aux_cost, aux_tree_map);
   1.235 +
   1.236 +      for (std::vector<SmartUGraph::UEdge>::iterator 
   1.237 +             it = aux_tree_edges.begin(); it != aux_tree_edges.end(); ++it) {
   1.238 +        Node node;
   1.239 +        node = _graph.source(cross[*it]);
   1.240 +        while (node != INVALID && !(*_filter)[node]) {
   1.241 +          _filter->set(node, true);
   1.242 +          node = (*_pred)[node] != INVALID ? 
   1.243 +            _graph.source((*_pred)[node]) : INVALID;
   1.244 +        }
   1.245 +        node = _graph.target(cross[*it]);
   1.246 +        while (node != INVALID && !(*_filter)[node]) {
   1.247 +          _filter->set(node, true);
   1.248 +          node = (*_pred)[node] != INVALID ? 
   1.249 +            _graph.source((*_pred)[node]) : INVALID;
   1.250 +        }
   1.251 +      }
   1.252 +
   1.253 +      prim(nodeSubUGraphAdaptor(_graph, *_filter), _cost, *_tree);
   1.254 +            
   1.255 +    }
   1.256 +
   1.257 +    /// \brief Checks if an edge is in the Steiner-tree or not.
   1.258 +    ///
   1.259 +    /// Checks if an edge is in the Steiner-tree or not.
   1.260 +    /// \param e is the edge that will be checked
   1.261 +    /// \return \c true if e is in the Steiner-tree, \c false otherwise
   1.262 +    bool tree(UEdge e){
   1.263 +      return (*_tree)[e];
   1.264 +    }
   1.265 +
   1.266 +    /// \brief Checks if the node is in the Steiner-tree or not.
   1.267 +    ///
   1.268 +    /// Checks if a node is in the Steiner-tree or not.
   1.269 +    /// \param n is the node that will be checked
   1.270 +    /// \return \c true if n is in the Steiner-tree, \c false otherwise
   1.271 +    bool tree(Node n){
   1.272 +      return (*_filter)[n];
   1.273 +    }
   1.274 +    
   1.275 +
   1.276 +  };
   1.277 +
   1.278 +} //END OF NAMESPACE LEMON
   1.279 +
   1.280 +#endif