kpeter@1033: /* -*- mode: C++; indent-tabs-mode: nil; -*- kpeter@1033: * kpeter@1033: * This file is a part of LEMON, a generic C++ optimization library. kpeter@1033: * kpeter@1033: * Copyright (C) 2003-2010 kpeter@1033: * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport kpeter@1033: * (Egervary Research Group on Combinatorial Optimization, EGRES). kpeter@1033: * kpeter@1033: * Permission to use, modify and distribute this software is granted kpeter@1033: * provided that this copyright notice appears in all copies. For kpeter@1033: * precise terms see the accompanying LICENSE file. kpeter@1033: * kpeter@1033: * This software is provided "AS IS" with no warranty of any kind, kpeter@1033: * express or implied, and with no claim as to its suitability for any kpeter@1033: * purpose. kpeter@1033: * kpeter@1033: */ kpeter@1033: f4c3@1031: #ifndef LEMON_INSERTION_TSP_H f4c3@1031: #define LEMON_INSERTION_TSP_H f4c3@1031: kpeter@1033: /// \ingroup tsp kpeter@1033: /// \file kpeter@1033: /// \brief Insertion algorithm for symmetric TSP kpeter@1033: kpeter@1033: #include f4c3@1031: #include f4c3@1031: #include f4c3@1031: #include f4c3@1031: f4c3@1031: namespace lemon { f4c3@1031: kpeter@1034: /// \ingroup tsp kpeter@1034: /// kpeter@1033: /// \brief Insertion algorithm for symmetric TSP. kpeter@1033: /// kpeter@1033: /// InsertionTsp implements the insertion heuristic for solving kpeter@1033: /// symmetric \ref tsp "TSP". kpeter@1033: /// kpeter@1033: /// This is a basic TSP heuristic that has many variants. kpeter@1033: /// It starts with a subtour containing a few nodes of the graph and it kpeter@1033: /// iteratively inserts the other nodes into this subtour according to a kpeter@1033: /// certain node selection rule. kpeter@1033: /// kpeter@1033: /// This implementation provides four different node selection rules, kpeter@1033: /// from which the most powerful one is used by default. kpeter@1033: /// For more information, see \ref SelectionRule. kpeter@1033: /// kpeter@1033: /// \tparam CM Type of the cost map. kpeter@1033: template kpeter@1033: class InsertionTsp kpeter@1033: { kpeter@1033: public: f4c3@1031: kpeter@1033: /// Type of the cost map f4c3@1031: typedef CM CostMap; kpeter@1033: /// Type of the edge costs f4c3@1031: typedef typename CM::Value Cost; f4c3@1031: f4c3@1031: private: f4c3@1031: kpeter@1033: GRAPH_TYPEDEFS(FullGraph); kpeter@1033: kpeter@1033: const FullGraph &_gr; kpeter@1033: const CostMap &_cost; kpeter@1033: std::vector _notused; kpeter@1033: std::vector _path; kpeter@1033: Cost _sum; kpeter@1033: kpeter@1033: public: kpeter@1033: kpeter@1033: /// \brief Constants for specifying the node selection rule. kpeter@1033: /// kpeter@1033: /// Enum type containing constants for specifying the node selection kpeter@1033: /// rule for the \ref run() function. kpeter@1033: /// kpeter@1033: /// During the algorithm, nodes are selected for addition to the current kpeter@1033: /// subtour according to the applied rule. kpeter@1034: /// In general, the FARTHEST method yields the best tours, thus it is the kpeter@1034: /// default option. The RANDOM rule usually gives somewhat worse results, kpeter@1034: /// but it is much faster than the others and it is the most robust. kpeter@1033: /// kpeter@1033: /// The desired selection rule can be specified as a parameter of the kpeter@1033: /// \ref run() function. kpeter@1033: enum SelectionRule { kpeter@1033: kpeter@1033: /// An unvisited node having minimum distance from the current kpeter@1033: /// subtour is selected at each step. kpeter@1033: /// The algorithm runs in O(n3) time using this kpeter@1033: /// selection rule. kpeter@1033: NEAREST, kpeter@1033: kpeter@1033: /// An unvisited node having maximum distance from the current kpeter@1033: /// subtour is selected at each step. kpeter@1033: /// The algorithm runs in O(n3) time using this kpeter@1033: /// selection rule. kpeter@1033: FARTHEST, kpeter@1033: kpeter@1033: /// An unvisited node whose insertion results in the least kpeter@1033: /// increase of the subtour's total cost is selected at each step. kpeter@1033: /// The algorithm runs in O(n3) time using this kpeter@1033: /// selection rule. kpeter@1033: CHEAPEST, kpeter@1033: kpeter@1033: /// An unvisited node is selected randomly without any evaluation kpeter@1033: /// at each step. kpeter@1033: /// The global \ref rnd "random number generator instance" is used. kpeter@1033: /// You can seed it before executing the algorithm, if you kpeter@1033: /// would like to. kpeter@1033: /// The algorithm runs in O(n2) time using this kpeter@1033: /// selection rule. kpeter@1033: RANDOM kpeter@1033: }; kpeter@1033: kpeter@1033: public: kpeter@1033: kpeter@1033: /// \brief Constructor kpeter@1033: /// kpeter@1033: /// Constructor. kpeter@1033: /// \param gr The \ref FullGraph "full graph" the algorithm runs on. kpeter@1033: /// \param cost The cost map. kpeter@1033: InsertionTsp(const FullGraph &gr, const CostMap &cost) kpeter@1033: : _gr(gr), _cost(cost) {} kpeter@1033: kpeter@1033: /// \name Execution Control kpeter@1033: /// @{ kpeter@1033: kpeter@1033: /// \brief Runs the algorithm. kpeter@1033: /// kpeter@1033: /// This function runs the algorithm. kpeter@1033: /// kpeter@1033: /// \param rule The node selection rule. For more information, see kpeter@1033: /// \ref SelectionRule. kpeter@1033: /// kpeter@1033: /// \return The total cost of the found tour. kpeter@1033: Cost run(SelectionRule rule = FARTHEST) { kpeter@1033: _path.clear(); kpeter@1033: kpeter@1033: if (_gr.nodeNum() == 0) return _sum = 0; kpeter@1033: else if (_gr.nodeNum() == 1) { kpeter@1033: _path.push_back(_gr(0)); kpeter@1033: return _sum = 0; kpeter@1033: } kpeter@1033: kpeter@1033: switch (rule) { kpeter@1033: case NEAREST: kpeter@1033: init(true); kpeter@1033: start(); kpeter@1033: break; kpeter@1033: case FARTHEST: kpeter@1033: init(false); kpeter@1033: start(); kpeter@1033: break; kpeter@1033: case CHEAPEST: kpeter@1033: init(true); kpeter@1033: start(); kpeter@1033: break; kpeter@1033: case RANDOM: kpeter@1033: init(true); kpeter@1033: start(); kpeter@1033: break; kpeter@1033: } kpeter@1033: return _sum; kpeter@1033: } kpeter@1033: kpeter@1033: /// @} kpeter@1033: kpeter@1033: /// \name Query Functions kpeter@1033: /// @{ kpeter@1033: kpeter@1033: /// \brief The total cost of the found tour. kpeter@1033: /// kpeter@1033: /// This function returns the total cost of the found tour. kpeter@1033: /// kpeter@1033: /// \pre run() must be called before using this function. kpeter@1033: Cost tourCost() const { kpeter@1033: return _sum; kpeter@1033: } kpeter@1033: kpeter@1033: /// \brief Returns a const reference to the node sequence of the kpeter@1033: /// found tour. kpeter@1033: /// kpeter@1034: /// This function returns a const reference to a vector kpeter@1033: /// that stores the node sequence of the found tour. kpeter@1033: /// kpeter@1033: /// \pre run() must be called before using this function. kpeter@1033: const std::vector& tourNodes() const { kpeter@1033: return _path; kpeter@1033: } kpeter@1033: kpeter@1033: /// \brief Gives back the node sequence of the found tour. kpeter@1033: /// kpeter@1033: /// This function copies the node sequence of the found tour into kpeter@1033: /// the given standard container. kpeter@1033: /// kpeter@1033: /// \pre run() must be called before using this function. kpeter@1033: template kpeter@1033: void tourNodes(Container &container) const { kpeter@1033: container.assign(_path.begin(), _path.end()); kpeter@1033: } kpeter@1033: kpeter@1033: /// \brief Gives back the found tour as a path. kpeter@1033: /// kpeter@1033: /// This function copies the found tour as a list of arcs/edges into kpeter@1033: /// the given \ref concept::Path "path structure". kpeter@1033: /// kpeter@1033: /// \pre run() must be called before using this function. kpeter@1033: template kpeter@1033: void tour(Path &path) const { kpeter@1033: path.clear(); kpeter@1033: for (int i = 0; i < int(_path.size()) - 1; ++i) { kpeter@1033: path.addBack(_gr.arc(_path[i], _path[i+1])); kpeter@1033: } kpeter@1033: if (int(_path.size()) >= 2) { kpeter@1033: path.addBack(_gr.arc(_path.back(), _path.front())); kpeter@1033: } kpeter@1033: } kpeter@1033: kpeter@1033: /// @} kpeter@1033: kpeter@1033: private: kpeter@1033: kpeter@1033: // Initializes the algorithm kpeter@1033: void init(bool min) { kpeter@1033: Edge min_edge = min ? mapMin(_gr, _cost) : mapMax(_gr, _cost); kpeter@1033: kpeter@1033: _path.clear(); kpeter@1033: _path.push_back(_gr.u(min_edge)); kpeter@1033: _path.push_back(_gr.v(min_edge)); kpeter@1033: kpeter@1033: _notused.clear(); kpeter@1033: for (NodeIt n(_gr); n!=INVALID; ++n) { kpeter@1033: if (n != _gr.u(min_edge) && n != _gr.v(min_edge)) { kpeter@1033: _notused.push_back(n); kpeter@1033: } kpeter@1033: } kpeter@1033: kpeter@1033: _sum = _cost[min_edge] * 2; kpeter@1033: } kpeter@1033: kpeter@1033: // Executes the algorithm kpeter@1033: template kpeter@1033: void start() { kpeter@1033: SelectionFunctor selectNode(_gr, _cost, _path, _notused); kpeter@1033: InsertionFunctor insertNode(_gr, _cost, _path, _sum); kpeter@1033: kpeter@1033: for (int i=0; i<_gr.nodeNum()-2; ++i) { kpeter@1033: insertNode.insert(selectNode.select()); kpeter@1033: } kpeter@1033: kpeter@1033: _sum = _cost[_gr.edge(_path.back(), _path.front())]; kpeter@1033: for (int i = 0; i < int(_path.size())-1; ++i) { kpeter@1033: _sum += _cost[_gr.edge(_path[i], _path[i+1])]; kpeter@1033: } kpeter@1033: } kpeter@1033: kpeter@1033: kpeter@1033: // Implementation of the nearest selection rule kpeter@1033: class NearestSelection { f4c3@1031: public: kpeter@1033: NearestSelection(const FullGraph &gr, const CostMap &cost, kpeter@1033: std::vector &path, std::vector ¬used) kpeter@1033: : _gr(gr), _cost(cost), _path(path), _notused(notused) {} f4c3@1031: kpeter@1033: Node select() const { kpeter@1033: Cost insert_val = 0; kpeter@1033: int insert_node = -1; kpeter@1033: kpeter@1033: for (unsigned int i=0; i<_notused.size(); ++i) { kpeter@1033: Cost min_val = _cost[_gr.edge(_notused[i], _path[0])]; kpeter@1033: int min_node = 0; kpeter@1033: kpeter@1033: for (unsigned int j=1; j<_path.size(); ++j) { kpeter@1033: Cost curr = _cost[_gr.edge(_notused[i], _path[j])]; kpeter@1033: if (min_val > curr) { kpeter@1033: min_val = curr; kpeter@1033: min_node = j; kpeter@1033: } kpeter@1033: } kpeter@1033: kpeter@1033: if (insert_val > min_val || insert_node == -1) { kpeter@1033: insert_val = min_val; kpeter@1033: insert_node = i; f4c3@1031: } f4c3@1031: } kpeter@1033: kpeter@1033: Node n = _notused[insert_node]; kpeter@1033: _notused.erase(_notused.begin()+insert_node); kpeter@1033: kpeter@1033: return n; f4c3@1031: } f4c3@1031: f4c3@1031: private: f4c3@1031: const FullGraph &_gr; f4c3@1031: const CostMap &_cost; kpeter@1033: std::vector &_path; f4c3@1031: std::vector &_notused; f4c3@1031: }; f4c3@1031: kpeter@1033: kpeter@1033: // Implementation of the farthest selection rule f4c3@1031: class FarthestSelection { f4c3@1031: public: f4c3@1031: FarthestSelection(const FullGraph &gr, const CostMap &cost, kpeter@1033: std::vector &path, std::vector ¬used) kpeter@1033: : _gr(gr), _cost(cost), _path(path), _notused(notused) {} kpeter@1033: f4c3@1031: Node select() const { kpeter@1033: Cost insert_val = 0; kpeter@1033: int insert_node = -1; f4c3@1031: f4c3@1031: for (unsigned int i=0; i<_notused.size(); ++i) { kpeter@1033: Cost min_val = _cost[_gr.edge(_notused[i], _path[0])]; f4c3@1031: int min_node = 0; kpeter@1033: kpeter@1033: for (unsigned int j=1; j<_path.size(); ++j) { kpeter@1033: Cost curr = _cost[_gr.edge(_notused[i], _path[j])]; kpeter@1033: if (min_val > curr) { kpeter@1033: min_val = curr; f4c3@1031: min_node = j; f4c3@1031: } f4c3@1031: } kpeter@1033: f4c3@1031: if (insert_val < min_val || insert_node == -1) { f4c3@1031: insert_val = min_val; f4c3@1031: insert_node = i; f4c3@1031: } f4c3@1031: } kpeter@1033: f4c3@1031: Node n = _notused[insert_node]; f4c3@1031: _notused.erase(_notused.begin()+insert_node); kpeter@1033: f4c3@1031: return n; f4c3@1031: } kpeter@1033: f4c3@1031: private: f4c3@1031: const FullGraph &_gr; f4c3@1031: const CostMap &_cost; kpeter@1033: std::vector &_path; f4c3@1031: std::vector &_notused; f4c3@1031: }; f4c3@1031: f4c3@1031: kpeter@1033: // Implementation of the cheapest selection rule f4c3@1031: class CheapestSelection { f4c3@1031: private: f4c3@1031: Cost costDiff(Node u, Node v, Node w) const { kpeter@1033: return f4c3@1031: _cost[_gr.edge(u, w)] + f4c3@1031: _cost[_gr.edge(v, w)] - f4c3@1031: _cost[_gr.edge(u, v)]; f4c3@1031: } f4c3@1031: f4c3@1031: public: f4c3@1031: CheapestSelection(const FullGraph &gr, const CostMap &cost, kpeter@1033: std::vector &path, std::vector ¬used) kpeter@1033: : _gr(gr), _cost(cost), _path(path), _notused(notused) {} kpeter@1033: f4c3@1031: Cost select() const { f4c3@1031: int insert_notused = -1; f4c3@1031: int best_insert_index = -1; kpeter@1033: Cost insert_val = 0; kpeter@1033: f4c3@1031: for (unsigned int i=0; i<_notused.size(); ++i) { f4c3@1031: int min = i; f4c3@1031: int best_insert_tmp = 0; f4c3@1031: Cost min_val = kpeter@1033: costDiff(_path.front(), _path.back(), _notused[i]); kpeter@1033: kpeter@1033: for (unsigned int j=1; j<_path.size(); ++j) { f4c3@1031: Cost tmp = kpeter@1033: costDiff(_path[j-1], _path[j], _notused[i]); f4c3@1031: f4c3@1031: if (min_val > tmp) { f4c3@1031: min = i; f4c3@1031: min_val = tmp; f4c3@1031: best_insert_tmp = j; f4c3@1031: } f4c3@1031: } f4c3@1031: kpeter@1033: if (insert_val > min_val || insert_notused == -1) { f4c3@1031: insert_notused = min; f4c3@1031: insert_val = min_val; f4c3@1031: best_insert_index = best_insert_tmp; f4c3@1031: } f4c3@1031: } f4c3@1031: kpeter@1033: _path.insert(_path.begin()+best_insert_index, kpeter@1033: _notused[insert_notused]); f4c3@1031: _notused.erase(_notused.begin()+insert_notused); f4c3@1031: f4c3@1031: return insert_val; f4c3@1031: } kpeter@1033: f4c3@1031: private: f4c3@1031: const FullGraph &_gr; f4c3@1031: const CostMap &_cost; kpeter@1033: std::vector &_path; f4c3@1031: std::vector &_notused; f4c3@1031: }; f4c3@1031: kpeter@1033: // Implementation of the random selection rule f4c3@1031: class RandomSelection { f4c3@1031: public: f4c3@1031: RandomSelection(const FullGraph &, const CostMap &, kpeter@1033: std::vector &, std::vector ¬used) kpeter@1033: : _notused(notused) {} kpeter@1033: f4c3@1031: Node select() const { f4c3@1031: const int index = rnd[_notused.size()]; f4c3@1031: Node n = _notused[index]; f4c3@1031: _notused.erase(_notused.begin()+index); f4c3@1031: return n; f4c3@1031: } f4c3@1031: private: f4c3@1031: std::vector &_notused; f4c3@1031: }; f4c3@1031: f4c3@1031: kpeter@1033: // Implementation of the default insertion method kpeter@1033: class DefaultInsertion { f4c3@1031: private: f4c3@1031: Cost costDiff(Node u, Node v, Node w) const { kpeter@1033: return f4c3@1031: _cost[_gr.edge(u, w)] + f4c3@1031: _cost[_gr.edge(v, w)] - f4c3@1031: _cost[_gr.edge(u, v)]; f4c3@1031: } kpeter@1033: f4c3@1031: public: kpeter@1033: DefaultInsertion(const FullGraph &gr, const CostMap &cost, kpeter@1033: std::vector &path, Cost &total_cost) : kpeter@1033: _gr(gr), _cost(cost), _path(path), _total(total_cost) {} kpeter@1033: f4c3@1031: void insert(Node n) const { f4c3@1031: int min = 0; f4c3@1031: Cost min_val = f4c3@1031: costDiff(_path.front(), _path.back(), n); kpeter@1033: f4c3@1031: for (unsigned int i=1; i<_path.size(); ++i) { f4c3@1031: Cost tmp = costDiff(_path[i-1], _path[i], n); f4c3@1031: if (tmp < min_val) { f4c3@1031: min = i; f4c3@1031: min_val = tmp; f4c3@1031: } f4c3@1031: } kpeter@1033: f4c3@1031: _path.insert(_path.begin()+min, n); kpeter@1033: _total += min_val; f4c3@1031: } kpeter@1033: f4c3@1031: private: f4c3@1031: const FullGraph &_gr; f4c3@1031: const CostMap &_cost; f4c3@1031: std::vector &_path; kpeter@1033: Cost &_total; f4c3@1031: }; kpeter@1033: kpeter@1033: // Implementation of a special insertion method for the cheapest kpeter@1033: // selection rule kpeter@1033: class CheapestInsertion { f4c3@1031: TEMPLATE_GRAPH_TYPEDEFS(FullGraph); f4c3@1031: public: kpeter@1033: CheapestInsertion(const FullGraph &, const CostMap &, kpeter@1033: std::vector &, Cost &total_cost) : kpeter@1033: _total(total_cost) {} kpeter@1033: f4c3@1031: void insert(Cost diff) const { kpeter@1033: _total += diff; f4c3@1031: } f4c3@1031: f4c3@1031: private: kpeter@1033: Cost &_total; kpeter@1033: }; kpeter@1033: f4c3@1031: }; kpeter@1033: f4c3@1031: }; // namespace lemon f4c3@1031: f4c3@1031: #endif