kpeter@1033
|
1 |
/* -*- mode: C++; indent-tabs-mode: nil; -*-
|
kpeter@1033
|
2 |
*
|
kpeter@1033
|
3 |
* This file is a part of LEMON, a generic C++ optimization library.
|
kpeter@1033
|
4 |
*
|
kpeter@1033
|
5 |
* Copyright (C) 2003-2010
|
kpeter@1033
|
6 |
* Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport
|
kpeter@1033
|
7 |
* (Egervary Research Group on Combinatorial Optimization, EGRES).
|
kpeter@1033
|
8 |
*
|
kpeter@1033
|
9 |
* Permission to use, modify and distribute this software is granted
|
kpeter@1033
|
10 |
* provided that this copyright notice appears in all copies. For
|
kpeter@1033
|
11 |
* precise terms see the accompanying LICENSE file.
|
kpeter@1033
|
12 |
*
|
kpeter@1033
|
13 |
* This software is provided "AS IS" with no warranty of any kind,
|
kpeter@1033
|
14 |
* express or implied, and with no claim as to its suitability for any
|
kpeter@1033
|
15 |
* purpose.
|
kpeter@1033
|
16 |
*
|
kpeter@1033
|
17 |
*/
|
kpeter@1033
|
18 |
|
f4c3@1031
|
19 |
#ifndef LEMON_INSERTION_TSP_H
|
f4c3@1031
|
20 |
#define LEMON_INSERTION_TSP_H
|
f4c3@1031
|
21 |
|
kpeter@1033
|
22 |
/// \ingroup tsp
|
kpeter@1033
|
23 |
/// \file
|
kpeter@1033
|
24 |
/// \brief Insertion algorithm for symmetric TSP
|
kpeter@1033
|
25 |
|
kpeter@1033
|
26 |
#include <vector>
|
kpeter@1036
|
27 |
#include <functional>
|
f4c3@1031
|
28 |
#include <lemon/full_graph.h>
|
f4c3@1031
|
29 |
#include <lemon/maps.h>
|
f4c3@1031
|
30 |
#include <lemon/random.h>
|
f4c3@1031
|
31 |
|
f4c3@1031
|
32 |
namespace lemon {
|
f4c3@1031
|
33 |
|
kpeter@1034
|
34 |
/// \ingroup tsp
|
kpeter@1034
|
35 |
///
|
kpeter@1033
|
36 |
/// \brief Insertion algorithm for symmetric TSP.
|
kpeter@1033
|
37 |
///
|
kpeter@1033
|
38 |
/// InsertionTsp implements the insertion heuristic for solving
|
kpeter@1033
|
39 |
/// symmetric \ref tsp "TSP".
|
kpeter@1033
|
40 |
///
|
kpeter@1036
|
41 |
/// This is a fast and effective tour construction method that has
|
kpeter@1036
|
42 |
/// many variants.
|
kpeter@1033
|
43 |
/// It starts with a subtour containing a few nodes of the graph and it
|
kpeter@1033
|
44 |
/// iteratively inserts the other nodes into this subtour according to a
|
kpeter@1033
|
45 |
/// certain node selection rule.
|
kpeter@1033
|
46 |
///
|
kpeter@1036
|
47 |
/// This method is among the fastest TSP algorithms, and it typically
|
kpeter@1036
|
48 |
/// provides quite good solutions (usually much better than
|
kpeter@1036
|
49 |
/// \ref NearestNeighborTsp and \ref GreedyTsp).
|
kpeter@1036
|
50 |
///
|
kpeter@1036
|
51 |
/// InsertionTsp implements four different node selection rules,
|
kpeter@1036
|
52 |
/// from which the most effective one (\e farthest \e node \e selection)
|
kpeter@1036
|
53 |
/// is used by default.
|
kpeter@1036
|
54 |
/// With this choice, the algorithm runs in O(n<sup>2</sup>) time.
|
kpeter@1033
|
55 |
/// For more information, see \ref SelectionRule.
|
kpeter@1033
|
56 |
///
|
kpeter@1033
|
57 |
/// \tparam CM Type of the cost map.
|
kpeter@1033
|
58 |
template <typename CM>
|
kpeter@1033
|
59 |
class InsertionTsp
|
kpeter@1033
|
60 |
{
|
kpeter@1033
|
61 |
public:
|
f4c3@1031
|
62 |
|
kpeter@1033
|
63 |
/// Type of the cost map
|
f4c3@1031
|
64 |
typedef CM CostMap;
|
kpeter@1033
|
65 |
/// Type of the edge costs
|
f4c3@1031
|
66 |
typedef typename CM::Value Cost;
|
f4c3@1031
|
67 |
|
f4c3@1031
|
68 |
private:
|
f4c3@1031
|
69 |
|
kpeter@1033
|
70 |
GRAPH_TYPEDEFS(FullGraph);
|
kpeter@1033
|
71 |
|
kpeter@1033
|
72 |
const FullGraph &_gr;
|
kpeter@1033
|
73 |
const CostMap &_cost;
|
kpeter@1033
|
74 |
std::vector<Node> _notused;
|
kpeter@1036
|
75 |
std::vector<Node> _tour;
|
kpeter@1033
|
76 |
Cost _sum;
|
kpeter@1033
|
77 |
|
kpeter@1033
|
78 |
public:
|
kpeter@1033
|
79 |
|
kpeter@1033
|
80 |
/// \brief Constants for specifying the node selection rule.
|
kpeter@1033
|
81 |
///
|
kpeter@1033
|
82 |
/// Enum type containing constants for specifying the node selection
|
kpeter@1033
|
83 |
/// rule for the \ref run() function.
|
kpeter@1033
|
84 |
///
|
kpeter@1033
|
85 |
/// During the algorithm, nodes are selected for addition to the current
|
kpeter@1033
|
86 |
/// subtour according to the applied rule.
|
kpeter@1036
|
87 |
/// The FARTHEST method is one of the fastest selection rules, and
|
kpeter@1036
|
88 |
/// it is typically the most effective, thus it is the default
|
kpeter@1036
|
89 |
/// option. The RANDOM rule usually gives slightly worse results,
|
kpeter@1036
|
90 |
/// but it is more robust.
|
kpeter@1033
|
91 |
///
|
kpeter@1033
|
92 |
/// The desired selection rule can be specified as a parameter of the
|
kpeter@1033
|
93 |
/// \ref run() function.
|
kpeter@1033
|
94 |
enum SelectionRule {
|
kpeter@1033
|
95 |
|
kpeter@1033
|
96 |
/// An unvisited node having minimum distance from the current
|
kpeter@1033
|
97 |
/// subtour is selected at each step.
|
kpeter@1036
|
98 |
/// The algorithm runs in O(n<sup>2</sup>) time using this
|
kpeter@1033
|
99 |
/// selection rule.
|
kpeter@1033
|
100 |
NEAREST,
|
kpeter@1033
|
101 |
|
kpeter@1033
|
102 |
/// An unvisited node having maximum distance from the current
|
kpeter@1033
|
103 |
/// subtour is selected at each step.
|
kpeter@1036
|
104 |
/// The algorithm runs in O(n<sup>2</sup>) time using this
|
kpeter@1033
|
105 |
/// selection rule.
|
kpeter@1033
|
106 |
FARTHEST,
|
kpeter@1033
|
107 |
|
kpeter@1033
|
108 |
/// An unvisited node whose insertion results in the least
|
kpeter@1033
|
109 |
/// increase of the subtour's total cost is selected at each step.
|
kpeter@1033
|
110 |
/// The algorithm runs in O(n<sup>3</sup>) time using this
|
kpeter@1036
|
111 |
/// selection rule, but in most cases, it is almost as fast as
|
kpeter@1036
|
112 |
/// with other rules.
|
kpeter@1033
|
113 |
CHEAPEST,
|
kpeter@1033
|
114 |
|
kpeter@1033
|
115 |
/// An unvisited node is selected randomly without any evaluation
|
kpeter@1033
|
116 |
/// at each step.
|
kpeter@1033
|
117 |
/// The global \ref rnd "random number generator instance" is used.
|
kpeter@1033
|
118 |
/// You can seed it before executing the algorithm, if you
|
kpeter@1033
|
119 |
/// would like to.
|
kpeter@1033
|
120 |
/// The algorithm runs in O(n<sup>2</sup>) time using this
|
kpeter@1033
|
121 |
/// selection rule.
|
kpeter@1033
|
122 |
RANDOM
|
kpeter@1033
|
123 |
};
|
kpeter@1033
|
124 |
|
kpeter@1033
|
125 |
public:
|
kpeter@1033
|
126 |
|
kpeter@1033
|
127 |
/// \brief Constructor
|
kpeter@1033
|
128 |
///
|
kpeter@1033
|
129 |
/// Constructor.
|
kpeter@1033
|
130 |
/// \param gr The \ref FullGraph "full graph" the algorithm runs on.
|
kpeter@1033
|
131 |
/// \param cost The cost map.
|
kpeter@1033
|
132 |
InsertionTsp(const FullGraph &gr, const CostMap &cost)
|
kpeter@1033
|
133 |
: _gr(gr), _cost(cost) {}
|
kpeter@1033
|
134 |
|
kpeter@1033
|
135 |
/// \name Execution Control
|
kpeter@1033
|
136 |
/// @{
|
kpeter@1033
|
137 |
|
kpeter@1033
|
138 |
/// \brief Runs the algorithm.
|
kpeter@1033
|
139 |
///
|
kpeter@1033
|
140 |
/// This function runs the algorithm.
|
kpeter@1033
|
141 |
///
|
kpeter@1033
|
142 |
/// \param rule The node selection rule. For more information, see
|
kpeter@1033
|
143 |
/// \ref SelectionRule.
|
kpeter@1033
|
144 |
///
|
kpeter@1033
|
145 |
/// \return The total cost of the found tour.
|
kpeter@1033
|
146 |
Cost run(SelectionRule rule = FARTHEST) {
|
kpeter@1036
|
147 |
_tour.clear();
|
kpeter@1033
|
148 |
|
kpeter@1033
|
149 |
if (_gr.nodeNum() == 0) return _sum = 0;
|
kpeter@1033
|
150 |
else if (_gr.nodeNum() == 1) {
|
kpeter@1036
|
151 |
_tour.push_back(_gr(0));
|
kpeter@1033
|
152 |
return _sum = 0;
|
kpeter@1033
|
153 |
}
|
kpeter@1033
|
154 |
|
kpeter@1033
|
155 |
switch (rule) {
|
kpeter@1033
|
156 |
case NEAREST:
|
kpeter@1033
|
157 |
init(true);
|
kpeter@1036
|
158 |
start<ComparingSelection<std::less<Cost> >,
|
kpeter@1036
|
159 |
DefaultInsertion>();
|
kpeter@1033
|
160 |
break;
|
kpeter@1033
|
161 |
case FARTHEST:
|
kpeter@1033
|
162 |
init(false);
|
kpeter@1036
|
163 |
start<ComparingSelection<std::greater<Cost> >,
|
kpeter@1036
|
164 |
DefaultInsertion>();
|
kpeter@1033
|
165 |
break;
|
kpeter@1033
|
166 |
case CHEAPEST:
|
kpeter@1033
|
167 |
init(true);
|
kpeter@1033
|
168 |
start<CheapestSelection, CheapestInsertion>();
|
kpeter@1033
|
169 |
break;
|
kpeter@1033
|
170 |
case RANDOM:
|
kpeter@1033
|
171 |
init(true);
|
kpeter@1033
|
172 |
start<RandomSelection, DefaultInsertion>();
|
kpeter@1033
|
173 |
break;
|
kpeter@1033
|
174 |
}
|
kpeter@1033
|
175 |
return _sum;
|
kpeter@1033
|
176 |
}
|
kpeter@1033
|
177 |
|
kpeter@1033
|
178 |
/// @}
|
kpeter@1033
|
179 |
|
kpeter@1033
|
180 |
/// \name Query Functions
|
kpeter@1033
|
181 |
/// @{
|
kpeter@1033
|
182 |
|
kpeter@1033
|
183 |
/// \brief The total cost of the found tour.
|
kpeter@1033
|
184 |
///
|
kpeter@1033
|
185 |
/// This function returns the total cost of the found tour.
|
kpeter@1033
|
186 |
///
|
kpeter@1033
|
187 |
/// \pre run() must be called before using this function.
|
kpeter@1033
|
188 |
Cost tourCost() const {
|
kpeter@1033
|
189 |
return _sum;
|
kpeter@1033
|
190 |
}
|
kpeter@1033
|
191 |
|
kpeter@1033
|
192 |
/// \brief Returns a const reference to the node sequence of the
|
kpeter@1033
|
193 |
/// found tour.
|
kpeter@1033
|
194 |
///
|
kpeter@1034
|
195 |
/// This function returns a const reference to a vector
|
kpeter@1033
|
196 |
/// that stores the node sequence of the found tour.
|
kpeter@1033
|
197 |
///
|
kpeter@1033
|
198 |
/// \pre run() must be called before using this function.
|
kpeter@1033
|
199 |
const std::vector<Node>& tourNodes() const {
|
kpeter@1036
|
200 |
return _tour;
|
kpeter@1033
|
201 |
}
|
kpeter@1033
|
202 |
|
kpeter@1033
|
203 |
/// \brief Gives back the node sequence of the found tour.
|
kpeter@1033
|
204 |
///
|
kpeter@1033
|
205 |
/// This function copies the node sequence of the found tour into
|
kpeter@1037
|
206 |
/// an STL container through the given output iterator. The
|
kpeter@1037
|
207 |
/// <tt>value_type</tt> of the container must be <tt>FullGraph::Node</tt>.
|
kpeter@1037
|
208 |
/// For example,
|
kpeter@1037
|
209 |
/// \code
|
kpeter@1037
|
210 |
/// std::vector<FullGraph::Node> nodes(countNodes(graph));
|
kpeter@1037
|
211 |
/// tsp.tourNodes(nodes.begin());
|
kpeter@1037
|
212 |
/// \endcode
|
kpeter@1037
|
213 |
/// or
|
kpeter@1037
|
214 |
/// \code
|
kpeter@1037
|
215 |
/// std::list<FullGraph::Node> nodes;
|
kpeter@1037
|
216 |
/// tsp.tourNodes(std::back_inserter(nodes));
|
kpeter@1037
|
217 |
/// \endcode
|
kpeter@1033
|
218 |
///
|
kpeter@1033
|
219 |
/// \pre run() must be called before using this function.
|
kpeter@1037
|
220 |
template <typename Iterator>
|
kpeter@1037
|
221 |
void tourNodes(Iterator out) const {
|
kpeter@1037
|
222 |
std::copy(_tour.begin(), _tour.end(), out);
|
kpeter@1033
|
223 |
}
|
kpeter@1033
|
224 |
|
kpeter@1033
|
225 |
/// \brief Gives back the found tour as a path.
|
kpeter@1033
|
226 |
///
|
kpeter@1033
|
227 |
/// This function copies the found tour as a list of arcs/edges into
|
kpeter@1033
|
228 |
/// the given \ref concept::Path "path structure".
|
kpeter@1033
|
229 |
///
|
kpeter@1033
|
230 |
/// \pre run() must be called before using this function.
|
kpeter@1033
|
231 |
template <typename Path>
|
kpeter@1033
|
232 |
void tour(Path &path) const {
|
kpeter@1033
|
233 |
path.clear();
|
kpeter@1036
|
234 |
for (int i = 0; i < int(_tour.size()) - 1; ++i) {
|
kpeter@1036
|
235 |
path.addBack(_gr.arc(_tour[i], _tour[i+1]));
|
kpeter@1033
|
236 |
}
|
kpeter@1036
|
237 |
if (int(_tour.size()) >= 2) {
|
kpeter@1036
|
238 |
path.addBack(_gr.arc(_tour.back(), _tour.front()));
|
kpeter@1033
|
239 |
}
|
kpeter@1033
|
240 |
}
|
kpeter@1033
|
241 |
|
kpeter@1033
|
242 |
/// @}
|
kpeter@1033
|
243 |
|
kpeter@1033
|
244 |
private:
|
kpeter@1033
|
245 |
|
kpeter@1033
|
246 |
// Initializes the algorithm
|
kpeter@1033
|
247 |
void init(bool min) {
|
kpeter@1033
|
248 |
Edge min_edge = min ? mapMin(_gr, _cost) : mapMax(_gr, _cost);
|
kpeter@1033
|
249 |
|
kpeter@1036
|
250 |
_tour.clear();
|
kpeter@1036
|
251 |
_tour.push_back(_gr.u(min_edge));
|
kpeter@1036
|
252 |
_tour.push_back(_gr.v(min_edge));
|
kpeter@1033
|
253 |
|
kpeter@1033
|
254 |
_notused.clear();
|
kpeter@1033
|
255 |
for (NodeIt n(_gr); n!=INVALID; ++n) {
|
kpeter@1033
|
256 |
if (n != _gr.u(min_edge) && n != _gr.v(min_edge)) {
|
kpeter@1033
|
257 |
_notused.push_back(n);
|
kpeter@1033
|
258 |
}
|
kpeter@1033
|
259 |
}
|
kpeter@1033
|
260 |
|
kpeter@1033
|
261 |
_sum = _cost[min_edge] * 2;
|
kpeter@1033
|
262 |
}
|
kpeter@1033
|
263 |
|
kpeter@1033
|
264 |
// Executes the algorithm
|
kpeter@1033
|
265 |
template <class SelectionFunctor, class InsertionFunctor>
|
kpeter@1033
|
266 |
void start() {
|
kpeter@1036
|
267 |
SelectionFunctor selectNode(_gr, _cost, _tour, _notused);
|
kpeter@1036
|
268 |
InsertionFunctor insertNode(_gr, _cost, _tour, _sum);
|
kpeter@1033
|
269 |
|
kpeter@1033
|
270 |
for (int i=0; i<_gr.nodeNum()-2; ++i) {
|
kpeter@1033
|
271 |
insertNode.insert(selectNode.select());
|
kpeter@1033
|
272 |
}
|
kpeter@1033
|
273 |
|
kpeter@1036
|
274 |
_sum = _cost[_gr.edge(_tour.back(), _tour.front())];
|
kpeter@1036
|
275 |
for (int i = 0; i < int(_tour.size())-1; ++i) {
|
kpeter@1036
|
276 |
_sum += _cost[_gr.edge(_tour[i], _tour[i+1])];
|
kpeter@1033
|
277 |
}
|
kpeter@1033
|
278 |
}
|
kpeter@1033
|
279 |
|
kpeter@1033
|
280 |
|
kpeter@1036
|
281 |
// Implementation of the nearest and farthest selection rule
|
kpeter@1036
|
282 |
template <typename Comparator>
|
kpeter@1036
|
283 |
class ComparingSelection {
|
f4c3@1031
|
284 |
public:
|
kpeter@1036
|
285 |
ComparingSelection(const FullGraph &gr, const CostMap &cost,
|
kpeter@1036
|
286 |
std::vector<Node> &tour, std::vector<Node> ¬used)
|
kpeter@1036
|
287 |
: _gr(gr), _cost(cost), _tour(tour), _notused(notused),
|
kpeter@1036
|
288 |
_dist(gr, 0), _compare()
|
kpeter@1036
|
289 |
{
|
kpeter@1036
|
290 |
// Compute initial distances for the unused nodes
|
kpeter@1033
|
291 |
for (unsigned int i=0; i<_notused.size(); ++i) {
|
kpeter@1036
|
292 |
Node u = _notused[i];
|
kpeter@1036
|
293 |
Cost min_dist = _cost[_gr.edge(u, _tour[0])];
|
kpeter@1036
|
294 |
for (unsigned int j=1; j<_tour.size(); ++j) {
|
kpeter@1036
|
295 |
Cost curr = _cost[_gr.edge(u, _tour[j])];
|
kpeter@1036
|
296 |
if (curr < min_dist) {
|
kpeter@1036
|
297 |
min_dist = curr;
|
kpeter@1033
|
298 |
}
|
kpeter@1033
|
299 |
}
|
kpeter@1036
|
300 |
_dist[u] = min_dist;
|
kpeter@1036
|
301 |
}
|
kpeter@1036
|
302 |
}
|
kpeter@1033
|
303 |
|
kpeter@1036
|
304 |
Node select() {
|
kpeter@1036
|
305 |
|
kpeter@1036
|
306 |
// Select an used node with minimum distance
|
kpeter@1036
|
307 |
Cost ins_dist = 0;
|
kpeter@1036
|
308 |
int ins_node = -1;
|
kpeter@1036
|
309 |
for (unsigned int i=0; i<_notused.size(); ++i) {
|
kpeter@1036
|
310 |
Cost curr = _dist[_notused[i]];
|
kpeter@1036
|
311 |
if (_compare(curr, ins_dist) || ins_node == -1) {
|
kpeter@1036
|
312 |
ins_dist = curr;
|
kpeter@1036
|
313 |
ins_node = i;
|
f4c3@1031
|
314 |
}
|
f4c3@1031
|
315 |
}
|
kpeter@1033
|
316 |
|
kpeter@1036
|
317 |
// Remove the selected node from the unused vector
|
kpeter@1036
|
318 |
Node sn = _notused[ins_node];
|
kpeter@1036
|
319 |
_notused[ins_node] = _notused.back();
|
kpeter@1036
|
320 |
_notused.pop_back();
|
kpeter@1033
|
321 |
|
kpeter@1036
|
322 |
// Update the distances of the remaining nodes
|
kpeter@1036
|
323 |
for (unsigned int i=0; i<_notused.size(); ++i) {
|
kpeter@1036
|
324 |
Node u = _notused[i];
|
kpeter@1036
|
325 |
Cost nc = _cost[_gr.edge(sn, u)];
|
kpeter@1036
|
326 |
if (nc < _dist[u]) {
|
kpeter@1036
|
327 |
_dist[u] = nc;
|
kpeter@1036
|
328 |
}
|
kpeter@1036
|
329 |
}
|
kpeter@1036
|
330 |
|
kpeter@1036
|
331 |
return sn;
|
f4c3@1031
|
332 |
}
|
f4c3@1031
|
333 |
|
f4c3@1031
|
334 |
private:
|
f4c3@1031
|
335 |
const FullGraph &_gr;
|
f4c3@1031
|
336 |
const CostMap &_cost;
|
kpeter@1036
|
337 |
std::vector<Node> &_tour;
|
f4c3@1031
|
338 |
std::vector<Node> &_notused;
|
kpeter@1036
|
339 |
FullGraph::NodeMap<Cost> _dist;
|
kpeter@1036
|
340 |
Comparator _compare;
|
f4c3@1031
|
341 |
};
|
f4c3@1031
|
342 |
|
kpeter@1033
|
343 |
// Implementation of the cheapest selection rule
|
f4c3@1031
|
344 |
class CheapestSelection {
|
f4c3@1031
|
345 |
private:
|
f4c3@1031
|
346 |
Cost costDiff(Node u, Node v, Node w) const {
|
kpeter@1033
|
347 |
return
|
f4c3@1031
|
348 |
_cost[_gr.edge(u, w)] +
|
f4c3@1031
|
349 |
_cost[_gr.edge(v, w)] -
|
f4c3@1031
|
350 |
_cost[_gr.edge(u, v)];
|
f4c3@1031
|
351 |
}
|
f4c3@1031
|
352 |
|
f4c3@1031
|
353 |
public:
|
f4c3@1031
|
354 |
CheapestSelection(const FullGraph &gr, const CostMap &cost,
|
kpeter@1036
|
355 |
std::vector<Node> &tour, std::vector<Node> ¬used)
|
kpeter@1036
|
356 |
: _gr(gr), _cost(cost), _tour(tour), _notused(notused),
|
kpeter@1036
|
357 |
_ins_cost(gr, 0), _ins_pos(gr, -1)
|
kpeter@1036
|
358 |
{
|
kpeter@1036
|
359 |
// Compute insertion cost and position for the unused nodes
|
f4c3@1031
|
360 |
for (unsigned int i=0; i<_notused.size(); ++i) {
|
kpeter@1036
|
361 |
Node u = _notused[i];
|
kpeter@1036
|
362 |
Cost min_cost = costDiff(_tour.back(), _tour.front(), u);
|
kpeter@1036
|
363 |
int min_pos = 0;
|
kpeter@1036
|
364 |
for (unsigned int j=1; j<_tour.size(); ++j) {
|
kpeter@1036
|
365 |
Cost curr_cost = costDiff(_tour[j-1], _tour[j], u);
|
kpeter@1036
|
366 |
if (curr_cost < min_cost) {
|
kpeter@1036
|
367 |
min_cost = curr_cost;
|
kpeter@1036
|
368 |
min_pos = j;
|
f4c3@1031
|
369 |
}
|
f4c3@1031
|
370 |
}
|
kpeter@1036
|
371 |
_ins_cost[u] = min_cost;
|
kpeter@1036
|
372 |
_ins_pos[u] = min_pos;
|
kpeter@1036
|
373 |
}
|
kpeter@1036
|
374 |
}
|
f4c3@1031
|
375 |
|
kpeter@1036
|
376 |
Cost select() {
|
kpeter@1036
|
377 |
|
kpeter@1036
|
378 |
// Select an used node with minimum insertion cost
|
kpeter@1036
|
379 |
Cost min_cost = 0;
|
kpeter@1036
|
380 |
int min_node = -1;
|
kpeter@1036
|
381 |
for (unsigned int i=0; i<_notused.size(); ++i) {
|
kpeter@1036
|
382 |
Cost curr_cost = _ins_cost[_notused[i]];
|
kpeter@1036
|
383 |
if (curr_cost < min_cost || min_node == -1) {
|
kpeter@1036
|
384 |
min_cost = curr_cost;
|
kpeter@1036
|
385 |
min_node = i;
|
f4c3@1031
|
386 |
}
|
f4c3@1031
|
387 |
}
|
f4c3@1031
|
388 |
|
kpeter@1036
|
389 |
// Remove the selected node from the unused vector
|
kpeter@1036
|
390 |
Node sn = _notused[min_node];
|
kpeter@1036
|
391 |
_notused[min_node] = _notused.back();
|
kpeter@1036
|
392 |
_notused.pop_back();
|
kpeter@1036
|
393 |
|
kpeter@1036
|
394 |
// Insert the selected node into the tour
|
kpeter@1036
|
395 |
const int ipos = _ins_pos[sn];
|
kpeter@1036
|
396 |
_tour.insert(_tour.begin() + ipos, sn);
|
f4c3@1031
|
397 |
|
kpeter@1036
|
398 |
// Update the insertion cost and position of the remaining nodes
|
kpeter@1036
|
399 |
for (unsigned int i=0; i<_notused.size(); ++i) {
|
kpeter@1036
|
400 |
Node u = _notused[i];
|
kpeter@1036
|
401 |
Cost curr_cost = _ins_cost[u];
|
kpeter@1036
|
402 |
int curr_pos = _ins_pos[u];
|
kpeter@1036
|
403 |
|
kpeter@1036
|
404 |
int ipos_prev = ipos == 0 ? _tour.size()-1 : ipos-1;
|
kpeter@1036
|
405 |
int ipos_next = ipos == int(_tour.size())-1 ? 0 : ipos+1;
|
kpeter@1036
|
406 |
Cost nc1 = costDiff(_tour[ipos_prev], _tour[ipos], u);
|
kpeter@1036
|
407 |
Cost nc2 = costDiff(_tour[ipos], _tour[ipos_next], u);
|
kpeter@1036
|
408 |
|
kpeter@1036
|
409 |
if (nc1 <= curr_cost || nc2 <= curr_cost) {
|
kpeter@1036
|
410 |
// A new position is better than the old one
|
kpeter@1036
|
411 |
if (nc1 <= nc2) {
|
kpeter@1036
|
412 |
curr_cost = nc1;
|
kpeter@1036
|
413 |
curr_pos = ipos;
|
kpeter@1036
|
414 |
} else {
|
kpeter@1036
|
415 |
curr_cost = nc2;
|
kpeter@1036
|
416 |
curr_pos = ipos_next;
|
kpeter@1036
|
417 |
}
|
kpeter@1036
|
418 |
}
|
kpeter@1036
|
419 |
else {
|
kpeter@1036
|
420 |
if (curr_pos == ipos) {
|
kpeter@1036
|
421 |
// The minimum should be found again
|
kpeter@1036
|
422 |
curr_cost = costDiff(_tour.back(), _tour.front(), u);
|
kpeter@1036
|
423 |
curr_pos = 0;
|
kpeter@1036
|
424 |
for (unsigned int j=1; j<_tour.size(); ++j) {
|
kpeter@1036
|
425 |
Cost tmp_cost = costDiff(_tour[j-1], _tour[j], u);
|
kpeter@1036
|
426 |
if (tmp_cost < curr_cost) {
|
kpeter@1036
|
427 |
curr_cost = tmp_cost;
|
kpeter@1036
|
428 |
curr_pos = j;
|
kpeter@1036
|
429 |
}
|
kpeter@1036
|
430 |
}
|
kpeter@1036
|
431 |
}
|
kpeter@1036
|
432 |
else if (curr_pos > ipos) {
|
kpeter@1036
|
433 |
++curr_pos;
|
kpeter@1036
|
434 |
}
|
kpeter@1036
|
435 |
}
|
kpeter@1036
|
436 |
|
kpeter@1036
|
437 |
_ins_cost[u] = curr_cost;
|
kpeter@1036
|
438 |
_ins_pos[u] = curr_pos;
|
kpeter@1036
|
439 |
}
|
kpeter@1036
|
440 |
|
kpeter@1036
|
441 |
return min_cost;
|
f4c3@1031
|
442 |
}
|
kpeter@1033
|
443 |
|
f4c3@1031
|
444 |
private:
|
f4c3@1031
|
445 |
const FullGraph &_gr;
|
f4c3@1031
|
446 |
const CostMap &_cost;
|
kpeter@1036
|
447 |
std::vector<Node> &_tour;
|
f4c3@1031
|
448 |
std::vector<Node> &_notused;
|
kpeter@1036
|
449 |
FullGraph::NodeMap<Cost> _ins_cost;
|
kpeter@1036
|
450 |
FullGraph::NodeMap<int> _ins_pos;
|
f4c3@1031
|
451 |
};
|
f4c3@1031
|
452 |
|
kpeter@1033
|
453 |
// Implementation of the random selection rule
|
f4c3@1031
|
454 |
class RandomSelection {
|
f4c3@1031
|
455 |
public:
|
f4c3@1031
|
456 |
RandomSelection(const FullGraph &, const CostMap &,
|
kpeter@1033
|
457 |
std::vector<Node> &, std::vector<Node> ¬used)
|
kpeter@1033
|
458 |
: _notused(notused) {}
|
kpeter@1033
|
459 |
|
f4c3@1031
|
460 |
Node select() const {
|
f4c3@1031
|
461 |
const int index = rnd[_notused.size()];
|
f4c3@1031
|
462 |
Node n = _notused[index];
|
kpeter@1036
|
463 |
_notused[index] = _notused.back();
|
kpeter@1036
|
464 |
_notused.pop_back();
|
f4c3@1031
|
465 |
return n;
|
f4c3@1031
|
466 |
}
|
kpeter@1036
|
467 |
|
f4c3@1031
|
468 |
private:
|
f4c3@1031
|
469 |
std::vector<Node> &_notused;
|
f4c3@1031
|
470 |
};
|
f4c3@1031
|
471 |
|
f4c3@1031
|
472 |
|
kpeter@1033
|
473 |
// Implementation of the default insertion method
|
kpeter@1033
|
474 |
class DefaultInsertion {
|
f4c3@1031
|
475 |
private:
|
f4c3@1031
|
476 |
Cost costDiff(Node u, Node v, Node w) const {
|
kpeter@1033
|
477 |
return
|
f4c3@1031
|
478 |
_cost[_gr.edge(u, w)] +
|
f4c3@1031
|
479 |
_cost[_gr.edge(v, w)] -
|
f4c3@1031
|
480 |
_cost[_gr.edge(u, v)];
|
f4c3@1031
|
481 |
}
|
kpeter@1033
|
482 |
|
f4c3@1031
|
483 |
public:
|
kpeter@1033
|
484 |
DefaultInsertion(const FullGraph &gr, const CostMap &cost,
|
kpeter@1036
|
485 |
std::vector<Node> &tour, Cost &total_cost) :
|
kpeter@1036
|
486 |
_gr(gr), _cost(cost), _tour(tour), _total(total_cost) {}
|
kpeter@1033
|
487 |
|
f4c3@1031
|
488 |
void insert(Node n) const {
|
f4c3@1031
|
489 |
int min = 0;
|
f4c3@1031
|
490 |
Cost min_val =
|
kpeter@1036
|
491 |
costDiff(_tour.front(), _tour.back(), n);
|
kpeter@1033
|
492 |
|
kpeter@1036
|
493 |
for (unsigned int i=1; i<_tour.size(); ++i) {
|
kpeter@1036
|
494 |
Cost tmp = costDiff(_tour[i-1], _tour[i], n);
|
f4c3@1031
|
495 |
if (tmp < min_val) {
|
f4c3@1031
|
496 |
min = i;
|
f4c3@1031
|
497 |
min_val = tmp;
|
f4c3@1031
|
498 |
}
|
f4c3@1031
|
499 |
}
|
kpeter@1033
|
500 |
|
kpeter@1036
|
501 |
_tour.insert(_tour.begin()+min, n);
|
kpeter@1033
|
502 |
_total += min_val;
|
f4c3@1031
|
503 |
}
|
kpeter@1033
|
504 |
|
f4c3@1031
|
505 |
private:
|
f4c3@1031
|
506 |
const FullGraph &_gr;
|
f4c3@1031
|
507 |
const CostMap &_cost;
|
kpeter@1036
|
508 |
std::vector<Node> &_tour;
|
kpeter@1033
|
509 |
Cost &_total;
|
f4c3@1031
|
510 |
};
|
kpeter@1033
|
511 |
|
kpeter@1033
|
512 |
// Implementation of a special insertion method for the cheapest
|
kpeter@1033
|
513 |
// selection rule
|
kpeter@1033
|
514 |
class CheapestInsertion {
|
f4c3@1031
|
515 |
TEMPLATE_GRAPH_TYPEDEFS(FullGraph);
|
f4c3@1031
|
516 |
public:
|
kpeter@1033
|
517 |
CheapestInsertion(const FullGraph &, const CostMap &,
|
kpeter@1033
|
518 |
std::vector<Node> &, Cost &total_cost) :
|
kpeter@1033
|
519 |
_total(total_cost) {}
|
kpeter@1033
|
520 |
|
f4c3@1031
|
521 |
void insert(Cost diff) const {
|
kpeter@1033
|
522 |
_total += diff;
|
f4c3@1031
|
523 |
}
|
f4c3@1031
|
524 |
|
f4c3@1031
|
525 |
private:
|
kpeter@1033
|
526 |
Cost &_total;
|
kpeter@1033
|
527 |
};
|
kpeter@1033
|
528 |
|
f4c3@1031
|
529 |
};
|
kpeter@1033
|
530 |
|
f4c3@1031
|
531 |
}; // namespace lemon
|
f4c3@1031
|
532 |
|
f4c3@1031
|
533 |
#endif
|