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
27 #include <lemon/full_graph.h>
28 #include <lemon/maps.h>
29 #include <lemon/random.h>
33 /// \brief Insertion algorithm for symmetric TSP.
35 /// InsertionTsp implements the insertion heuristic for solving
36 /// symmetric \ref tsp "TSP".
38 /// This is a basic TSP heuristic that has many variants.
39 /// It starts with a subtour containing a few nodes of the graph and it
40 /// iteratively inserts the other nodes into this subtour according to a
41 /// certain node selection rule.
43 /// This implementation provides four different node selection rules,
44 /// from which the most powerful one is used by default.
45 /// For more information, see \ref SelectionRule.
47 /// \tparam CM Type of the cost map.
48 template <typename CM>
53 /// Type of the cost map
55 /// Type of the edge costs
56 typedef typename CM::Value Cost;
60 GRAPH_TYPEDEFS(FullGraph);
64 std::vector<Node> _notused;
65 std::vector<Node> _path;
70 /// \brief Constants for specifying the node selection rule.
72 /// Enum type containing constants for specifying the node selection
73 /// rule for the \ref run() function.
75 /// During the algorithm, nodes are selected for addition to the current
76 /// subtour according to the applied rule.
77 /// In general, the FARTHEST yields the best tours, thus it is the
78 /// default option. RANDOM usually gives somewhat worse results, but
79 /// it is much faster than the others and it is the most robust.
81 /// The desired selection rule can be specified as a parameter of the
82 /// \ref run() function.
85 /// An unvisited node having minimum distance from the current
86 /// subtour is selected at each step.
87 /// The algorithm runs in O(n<sup>3</sup>) time using this
91 /// An unvisited node having maximum distance from the current
92 /// subtour is selected at each step.
93 /// The algorithm runs in O(n<sup>3</sup>) time using this
97 /// An unvisited node whose insertion results in the least
98 /// increase of the subtour's total cost is selected at each step.
99 /// The algorithm runs in O(n<sup>3</sup>) time using this
103 /// An unvisited node is selected randomly without any evaluation
105 /// The global \ref rnd "random number generator instance" is used.
106 /// You can seed it before executing the algorithm, if you
108 /// The algorithm runs in O(n<sup>2</sup>) time using this
115 /// \brief Constructor
118 /// \param gr The \ref FullGraph "full graph" the algorithm runs on.
119 /// \param cost The cost map.
120 InsertionTsp(const FullGraph &gr, const CostMap &cost)
121 : _gr(gr), _cost(cost) {}
123 /// \name Execution Control
126 /// \brief Runs the algorithm.
128 /// This function runs the algorithm.
130 /// \param rule The node selection rule. For more information, see
131 /// \ref SelectionRule.
133 /// \return The total cost of the found tour.
134 Cost run(SelectionRule rule = FARTHEST) {
137 if (_gr.nodeNum() == 0) return _sum = 0;
138 else if (_gr.nodeNum() == 1) {
139 _path.push_back(_gr(0));
146 start<NearestSelection, DefaultInsertion>();
150 start<FarthestSelection, DefaultInsertion>();
154 start<CheapestSelection, CheapestInsertion>();
158 start<RandomSelection, DefaultInsertion>();
166 /// \name Query Functions
169 /// \brief The total cost of the found tour.
171 /// This function returns the total cost of the found tour.
173 /// \pre run() must be called before using this function.
174 Cost tourCost() const {
178 /// \brief Returns a const reference to the node sequence of the
181 /// This function returns a const reference to the internal structure
182 /// that stores the node sequence of the found tour.
184 /// \pre run() must be called before using this function.
185 const std::vector<Node>& tourNodes() const {
189 /// \brief Gives back the node sequence of the found tour.
191 /// This function copies the node sequence of the found tour into
192 /// the given standard container.
194 /// \pre run() must be called before using this function.
195 template <typename Container>
196 void tourNodes(Container &container) const {
197 container.assign(_path.begin(), _path.end());
200 /// \brief Gives back the found tour as a path.
202 /// This function copies the found tour as a list of arcs/edges into
203 /// the given \ref concept::Path "path structure".
205 /// \pre run() must be called before using this function.
206 template <typename Path>
207 void tour(Path &path) const {
209 for (int i = 0; i < int(_path.size()) - 1; ++i) {
210 path.addBack(_gr.arc(_path[i], _path[i+1]));
212 if (int(_path.size()) >= 2) {
213 path.addBack(_gr.arc(_path.back(), _path.front()));
221 // Initializes the algorithm
222 void init(bool min) {
223 Edge min_edge = min ? mapMin(_gr, _cost) : mapMax(_gr, _cost);
226 _path.push_back(_gr.u(min_edge));
227 _path.push_back(_gr.v(min_edge));
230 for (NodeIt n(_gr); n!=INVALID; ++n) {
231 if (n != _gr.u(min_edge) && n != _gr.v(min_edge)) {
232 _notused.push_back(n);
236 _sum = _cost[min_edge] * 2;
239 // Executes the algorithm
240 template <class SelectionFunctor, class InsertionFunctor>
242 SelectionFunctor selectNode(_gr, _cost, _path, _notused);
243 InsertionFunctor insertNode(_gr, _cost, _path, _sum);
245 for (int i=0; i<_gr.nodeNum()-2; ++i) {
246 insertNode.insert(selectNode.select());
249 _sum = _cost[_gr.edge(_path.back(), _path.front())];
250 for (int i = 0; i < int(_path.size())-1; ++i) {
251 _sum += _cost[_gr.edge(_path[i], _path[i+1])];
256 // Implementation of the nearest selection rule
257 class NearestSelection {
259 NearestSelection(const FullGraph &gr, const CostMap &cost,
260 std::vector<Node> &path, std::vector<Node> ¬used)
261 : _gr(gr), _cost(cost), _path(path), _notused(notused) {}
263 Node select() const {
265 int insert_node = -1;
267 for (unsigned int i=0; i<_notused.size(); ++i) {
268 Cost min_val = _cost[_gr.edge(_notused[i], _path[0])];
271 for (unsigned int j=1; j<_path.size(); ++j) {
272 Cost curr = _cost[_gr.edge(_notused[i], _path[j])];
273 if (min_val > curr) {
279 if (insert_val > min_val || insert_node == -1) {
280 insert_val = min_val;
285 Node n = _notused[insert_node];
286 _notused.erase(_notused.begin()+insert_node);
292 const FullGraph &_gr;
293 const CostMap &_cost;
294 std::vector<Node> &_path;
295 std::vector<Node> &_notused;
299 // Implementation of the farthest selection rule
300 class FarthestSelection {
302 FarthestSelection(const FullGraph &gr, const CostMap &cost,
303 std::vector<Node> &path, std::vector<Node> ¬used)
304 : _gr(gr), _cost(cost), _path(path), _notused(notused) {}
306 Node select() const {
308 int insert_node = -1;
310 for (unsigned int i=0; i<_notused.size(); ++i) {
311 Cost min_val = _cost[_gr.edge(_notused[i], _path[0])];
314 for (unsigned int j=1; j<_path.size(); ++j) {
315 Cost curr = _cost[_gr.edge(_notused[i], _path[j])];
316 if (min_val > curr) {
322 if (insert_val < min_val || insert_node == -1) {
323 insert_val = min_val;
328 Node n = _notused[insert_node];
329 _notused.erase(_notused.begin()+insert_node);
335 const FullGraph &_gr;
336 const CostMap &_cost;
337 std::vector<Node> &_path;
338 std::vector<Node> &_notused;
342 // Implementation of the cheapest selection rule
343 class CheapestSelection {
345 Cost costDiff(Node u, Node v, Node w) const {
347 _cost[_gr.edge(u, w)] +
348 _cost[_gr.edge(v, w)] -
349 _cost[_gr.edge(u, v)];
353 CheapestSelection(const FullGraph &gr, const CostMap &cost,
354 std::vector<Node> &path, std::vector<Node> ¬used)
355 : _gr(gr), _cost(cost), _path(path), _notused(notused) {}
357 Cost select() const {
358 int insert_notused = -1;
359 int best_insert_index = -1;
362 for (unsigned int i=0; i<_notused.size(); ++i) {
364 int best_insert_tmp = 0;
366 costDiff(_path.front(), _path.back(), _notused[i]);
368 for (unsigned int j=1; j<_path.size(); ++j) {
370 costDiff(_path[j-1], _path[j], _notused[i]);
379 if (insert_val > min_val || insert_notused == -1) {
380 insert_notused = min;
381 insert_val = min_val;
382 best_insert_index = best_insert_tmp;
386 _path.insert(_path.begin()+best_insert_index,
387 _notused[insert_notused]);
388 _notused.erase(_notused.begin()+insert_notused);
394 const FullGraph &_gr;
395 const CostMap &_cost;
396 std::vector<Node> &_path;
397 std::vector<Node> &_notused;
400 // Implementation of the random selection rule
401 class RandomSelection {
403 RandomSelection(const FullGraph &, const CostMap &,
404 std::vector<Node> &, std::vector<Node> ¬used)
405 : _notused(notused) {}
407 Node select() const {
408 const int index = rnd[_notused.size()];
409 Node n = _notused[index];
410 _notused.erase(_notused.begin()+index);
414 std::vector<Node> &_notused;
418 // Implementation of the default insertion method
419 class DefaultInsertion {
421 Cost costDiff(Node u, Node v, Node w) const {
423 _cost[_gr.edge(u, w)] +
424 _cost[_gr.edge(v, w)] -
425 _cost[_gr.edge(u, v)];
429 DefaultInsertion(const FullGraph &gr, const CostMap &cost,
430 std::vector<Node> &path, Cost &total_cost) :
431 _gr(gr), _cost(cost), _path(path), _total(total_cost) {}
433 void insert(Node n) const {
436 costDiff(_path.front(), _path.back(), n);
438 for (unsigned int i=1; i<_path.size(); ++i) {
439 Cost tmp = costDiff(_path[i-1], _path[i], n);
446 _path.insert(_path.begin()+min, n);
451 const FullGraph &_gr;
452 const CostMap &_cost;
453 std::vector<Node> &_path;
457 // Implementation of a special insertion method for the cheapest
459 class CheapestInsertion {
460 TEMPLATE_GRAPH_TYPEDEFS(FullGraph);
462 CheapestInsertion(const FullGraph &, const CostMap &,
463 std::vector<Node> &, Cost &total_cost) :
464 _total(total_cost) {}
466 void insert(Cost diff) const {
476 }; // namespace lemon