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