1 /* -*- mode: C++; indent-tabs-mode: nil; -*-
3 * This file is a part of LEMON, a generic C++ optimization library.
5 * Copyright (C) 2003-2010
6 * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport
7 * (Egervary Research Group on Combinatorial Optimization, EGRES).
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.
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
19 #ifndef LEMON_INSERTION_TSP_H
20 #define LEMON_INSERTION_TSP_H
24 /// \brief Insertion algorithm for symmetric TSP
28 #include <lemon/full_graph.h>
29 #include <lemon/maps.h>
30 #include <lemon/random.h>
36 /// \brief Insertion algorithm for symmetric TSP.
38 /// InsertionTsp implements the insertion heuristic for solving
39 /// symmetric \ref tsp "TSP".
41 /// This is a fast and effective tour construction method that has
43 /// It starts with a subtour containing a few nodes of the graph and it
44 /// iteratively inserts the other nodes into this subtour according to a
45 /// certain node selection rule.
47 /// This method is among the fastest TSP algorithms, and it typically
48 /// provides quite good solutions (usually much better than
49 /// \ref NearestNeighborTsp and \ref GreedyTsp).
51 /// InsertionTsp implements four different node selection rules,
52 /// from which the most effective one (\e farthest \e node \e selection)
53 /// is used by default.
54 /// With this choice, the algorithm runs in O(n<sup>2</sup>) time.
55 /// For more information, see \ref SelectionRule.
57 /// \tparam CM Type of the cost map.
58 template <typename CM>
63 /// Type of the cost map
65 /// Type of the edge costs
66 typedef typename CM::Value Cost;
70 GRAPH_TYPEDEFS(FullGraph);
74 std::vector<Node> _notused;
75 std::vector<Node> _tour;
80 /// \brief Constants for specifying the node selection rule.
82 /// Enum type containing constants for specifying the node selection
83 /// rule for the \ref run() function.
85 /// During the algorithm, nodes are selected for addition to the current
86 /// subtour according to the applied rule.
87 /// The FARTHEST method is one of the fastest selection rules, and
88 /// it is typically the most effective, thus it is the default
89 /// option. The RANDOM rule usually gives slightly worse results,
90 /// but it is more robust.
92 /// The desired selection rule can be specified as a parameter of the
93 /// \ref run() function.
96 /// An unvisited node having minimum distance from the current
97 /// subtour is selected at each step.
98 /// The algorithm runs in O(n<sup>2</sup>) time using this
102 /// An unvisited node having maximum distance from the current
103 /// subtour is selected at each step.
104 /// The algorithm runs in O(n<sup>2</sup>) time using this
108 /// An unvisited node whose insertion results in the least
109 /// increase of the subtour's total cost is selected at each step.
110 /// The algorithm runs in O(n<sup>3</sup>) time using this
111 /// selection rule, but in most cases, it is almost as fast as
112 /// with other rules.
115 /// An unvisited node is selected randomly without any evaluation
117 /// The global \ref rnd "random number generator instance" is used.
118 /// You can seed it before executing the algorithm, if you
120 /// The algorithm runs in O(n<sup>2</sup>) time using this
127 /// \brief Constructor
130 /// \param gr The \ref FullGraph "full graph" the algorithm runs on.
131 /// \param cost The cost map.
132 InsertionTsp(const FullGraph &gr, const CostMap &cost)
133 : _gr(gr), _cost(cost) {}
135 /// \name Execution Control
138 /// \brief Runs the algorithm.
140 /// This function runs the algorithm.
142 /// \param rule The node selection rule. For more information, see
143 /// \ref SelectionRule.
145 /// \return The total cost of the found tour.
146 Cost run(SelectionRule rule = FARTHEST) {
149 if (_gr.nodeNum() == 0) return _sum = 0;
150 else if (_gr.nodeNum() == 1) {
151 _tour.push_back(_gr(0));
158 start<ComparingSelection<std::less<Cost> >,
163 start<ComparingSelection<std::greater<Cost> >,
168 start<CheapestSelection, CheapestInsertion>();
172 start<RandomSelection, DefaultInsertion>();
180 /// \name Query Functions
183 /// \brief The total cost of the found tour.
185 /// This function returns the total cost of the found tour.
187 /// \pre run() must be called before using this function.
188 Cost tourCost() const {
192 /// \brief Returns a const reference to the node sequence of the
195 /// This function returns a const reference to a vector
196 /// that stores the node sequence of the found tour.
198 /// \pre run() must be called before using this function.
199 const std::vector<Node>& tourNodes() const {
203 /// \brief Gives back the node sequence of the found tour.
205 /// This function copies the node sequence of the found tour into
206 /// an STL container through the given output iterator. The
207 /// <tt>value_type</tt> of the container must be <tt>FullGraph::Node</tt>.
210 /// std::vector<FullGraph::Node> nodes(countNodes(graph));
211 /// tsp.tourNodes(nodes.begin());
215 /// std::list<FullGraph::Node> nodes;
216 /// tsp.tourNodes(std::back_inserter(nodes));
219 /// \pre run() must be called before using this function.
220 template <typename Iterator>
221 void tourNodes(Iterator out) const {
222 std::copy(_tour.begin(), _tour.end(), out);
225 /// \brief Gives back the found tour as a path.
227 /// This function copies the found tour as a list of arcs/edges into
228 /// the given \ref lemon::concepts::Path "path structure".
230 /// \pre run() must be called before using this function.
231 template <typename Path>
232 void tour(Path &path) const {
234 for (int i = 0; i < int(_tour.size()) - 1; ++i) {
235 path.addBack(_gr.arc(_tour[i], _tour[i+1]));
237 if (int(_tour.size()) >= 2) {
238 path.addBack(_gr.arc(_tour.back(), _tour.front()));
246 // Initializes the algorithm
247 void init(bool min) {
248 Edge min_edge = min ? mapMin(_gr, _cost) : mapMax(_gr, _cost);
251 _tour.push_back(_gr.u(min_edge));
252 _tour.push_back(_gr.v(min_edge));
255 for (NodeIt n(_gr); n!=INVALID; ++n) {
256 if (n != _gr.u(min_edge) && n != _gr.v(min_edge)) {
257 _notused.push_back(n);
261 _sum = _cost[min_edge] * 2;
264 // Executes the algorithm
265 template <class SelectionFunctor, class InsertionFunctor>
267 SelectionFunctor selectNode(_gr, _cost, _tour, _notused);
268 InsertionFunctor insertNode(_gr, _cost, _tour, _sum);
270 for (int i=0; i<_gr.nodeNum()-2; ++i) {
271 insertNode.insert(selectNode.select());
274 _sum = _cost[_gr.edge(_tour.back(), _tour.front())];
275 for (int i = 0; i < int(_tour.size())-1; ++i) {
276 _sum += _cost[_gr.edge(_tour[i], _tour[i+1])];
281 // Implementation of the nearest and farthest selection rule
282 template <typename Comparator>
283 class ComparingSelection {
285 ComparingSelection(const FullGraph &gr, const CostMap &cost,
286 std::vector<Node> &tour, std::vector<Node> ¬used)
287 : _gr(gr), _cost(cost), _tour(tour), _notused(notused),
288 _dist(gr, 0), _compare()
290 // Compute initial distances for the unused nodes
291 for (unsigned int i=0; i<_notused.size(); ++i) {
292 Node u = _notused[i];
293 Cost min_dist = _cost[_gr.edge(u, _tour[0])];
294 for (unsigned int j=1; j<_tour.size(); ++j) {
295 Cost curr = _cost[_gr.edge(u, _tour[j])];
296 if (curr < min_dist) {
306 // Select an used node with minimum distance
309 for (unsigned int i=0; i<_notused.size(); ++i) {
310 Cost curr = _dist[_notused[i]];
311 if (_compare(curr, ins_dist) || ins_node == -1) {
317 // Remove the selected node from the unused vector
318 Node sn = _notused[ins_node];
319 _notused[ins_node] = _notused.back();
322 // Update the distances of the remaining nodes
323 for (unsigned int i=0; i<_notused.size(); ++i) {
324 Node u = _notused[i];
325 Cost nc = _cost[_gr.edge(sn, u)];
335 const FullGraph &_gr;
336 const CostMap &_cost;
337 std::vector<Node> &_tour;
338 std::vector<Node> &_notused;
339 FullGraph::NodeMap<Cost> _dist;
343 // Implementation of the cheapest selection rule
344 class CheapestSelection {
346 Cost costDiff(Node u, Node v, Node w) const {
348 _cost[_gr.edge(u, w)] +
349 _cost[_gr.edge(v, w)] -
350 _cost[_gr.edge(u, v)];
354 CheapestSelection(const FullGraph &gr, const CostMap &cost,
355 std::vector<Node> &tour, std::vector<Node> ¬used)
356 : _gr(gr), _cost(cost), _tour(tour), _notused(notused),
357 _ins_cost(gr, 0), _ins_pos(gr, -1)
359 // Compute insertion cost and position for the unused nodes
360 for (unsigned int i=0; i<_notused.size(); ++i) {
361 Node u = _notused[i];
362 Cost min_cost = costDiff(_tour.back(), _tour.front(), u);
364 for (unsigned int j=1; j<_tour.size(); ++j) {
365 Cost curr_cost = costDiff(_tour[j-1], _tour[j], u);
366 if (curr_cost < min_cost) {
367 min_cost = curr_cost;
371 _ins_cost[u] = min_cost;
372 _ins_pos[u] = min_pos;
378 // Select an used node with minimum insertion cost
381 for (unsigned int i=0; i<_notused.size(); ++i) {
382 Cost curr_cost = _ins_cost[_notused[i]];
383 if (curr_cost < min_cost || min_node == -1) {
384 min_cost = curr_cost;
389 // Remove the selected node from the unused vector
390 Node sn = _notused[min_node];
391 _notused[min_node] = _notused.back();
394 // Insert the selected node into the tour
395 const int ipos = _ins_pos[sn];
396 _tour.insert(_tour.begin() + ipos, sn);
398 // Update the insertion cost and position of the remaining nodes
399 for (unsigned int i=0; i<_notused.size(); ++i) {
400 Node u = _notused[i];
401 Cost curr_cost = _ins_cost[u];
402 int curr_pos = _ins_pos[u];
404 int ipos_prev = ipos == 0 ? _tour.size()-1 : ipos-1;
405 int ipos_next = ipos == int(_tour.size())-1 ? 0 : ipos+1;
406 Cost nc1 = costDiff(_tour[ipos_prev], _tour[ipos], u);
407 Cost nc2 = costDiff(_tour[ipos], _tour[ipos_next], u);
409 if (nc1 <= curr_cost || nc2 <= curr_cost) {
410 // A new position is better than the old one
416 curr_pos = ipos_next;
420 if (curr_pos == ipos) {
421 // The minimum should be found again
422 curr_cost = costDiff(_tour.back(), _tour.front(), u);
424 for (unsigned int j=1; j<_tour.size(); ++j) {
425 Cost tmp_cost = costDiff(_tour[j-1], _tour[j], u);
426 if (tmp_cost < curr_cost) {
427 curr_cost = tmp_cost;
432 else if (curr_pos > ipos) {
437 _ins_cost[u] = curr_cost;
438 _ins_pos[u] = curr_pos;
445 const FullGraph &_gr;
446 const CostMap &_cost;
447 std::vector<Node> &_tour;
448 std::vector<Node> &_notused;
449 FullGraph::NodeMap<Cost> _ins_cost;
450 FullGraph::NodeMap<int> _ins_pos;
453 // Implementation of the random selection rule
454 class RandomSelection {
456 RandomSelection(const FullGraph &, const CostMap &,
457 std::vector<Node> &, std::vector<Node> ¬used)
458 : _notused(notused) {}
460 Node select() const {
461 const int index = rnd[_notused.size()];
462 Node n = _notused[index];
463 _notused[index] = _notused.back();
469 std::vector<Node> &_notused;
473 // Implementation of the default insertion method
474 class DefaultInsertion {
476 Cost costDiff(Node u, Node v, Node w) const {
478 _cost[_gr.edge(u, w)] +
479 _cost[_gr.edge(v, w)] -
480 _cost[_gr.edge(u, v)];
484 DefaultInsertion(const FullGraph &gr, const CostMap &cost,
485 std::vector<Node> &tour, Cost &total_cost) :
486 _gr(gr), _cost(cost), _tour(tour), _total(total_cost) {}
488 void insert(Node n) const {
491 costDiff(_tour.front(), _tour.back(), n);
493 for (unsigned int i=1; i<_tour.size(); ++i) {
494 Cost tmp = costDiff(_tour[i-1], _tour[i], n);
501 _tour.insert(_tour.begin()+min, n);
506 const FullGraph &_gr;
507 const CostMap &_cost;
508 std::vector<Node> &_tour;
512 // Implementation of a special insertion method for the cheapest
514 class CheapestInsertion {
515 TEMPLATE_GRAPH_TYPEDEFS(FullGraph);
517 CheapestInsertion(const FullGraph &, const CostMap &,
518 std::vector<Node> &, Cost &total_cost) :
519 _total(total_cost) {}
521 void insert(Cost diff) const {
531 }; // namespace lemon