kpeter@1201: /* -*- mode: C++; indent-tabs-mode: nil; -*- kpeter@1201: * kpeter@1201: * This file is a part of LEMON, a generic C++ optimization library. kpeter@1201: * kpeter@1201: * Copyright (C) 2003-2010 kpeter@1201: * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport kpeter@1201: * (Egervary Research Group on Combinatorial Optimization, EGRES). kpeter@1201: * kpeter@1201: * Permission to use, modify and distribute this software is granted kpeter@1201: * provided that this copyright notice appears in all copies. For kpeter@1201: * precise terms see the accompanying LICENSE file. kpeter@1201: * kpeter@1201: * This software is provided "AS IS" with no warranty of any kind, kpeter@1201: * express or implied, and with no claim as to its suitability for any kpeter@1201: * purpose. kpeter@1201: * kpeter@1201: */ kpeter@1201: f4c3@1199: #ifndef LEMON_OPT2_TSP_H f4c3@1199: #define LEMON_OPT2_TSP_H f4c3@1199: kpeter@1201: /// \ingroup tsp kpeter@1201: /// \file kpeter@1202: /// \brief 2-opt algorithm for symmetric TSP. kpeter@1201: f4c3@1199: #include f4c3@1199: #include f4c3@1199: f4c3@1199: namespace lemon { kpeter@1201: kpeter@1202: /// \ingroup tsp kpeter@1202: /// kpeter@1201: /// \brief 2-opt algorithm for symmetric TSP. kpeter@1201: /// kpeter@1201: /// Opt2Tsp implements the 2-opt heuristic for solving kpeter@1201: /// symmetric \ref tsp "TSP". kpeter@1201: /// kpeter@1201: /// This algorithm starts with an initial tour and iteratively improves it. kpeter@1201: /// At each step, it removes two edges and the reconnects the created two kpeter@1201: /// paths in the other way if the resulting tour is shorter. kpeter@1201: /// The algorithm finishes when no such 2-opt move can be applied, and so kpeter@1201: /// the tour is 2-optimal. kpeter@1201: /// kpeter@1201: /// If no starting tour is given to the \ref run() function, then the kpeter@1201: /// algorithm uses the node sequence determined by the node IDs. kpeter@1201: /// Oherwise, it starts with the given tour. kpeter@1201: /// kpeter@1204: /// This is a rather slow but effective method. kpeter@1204: /// Its typical usage is the improvement of the result of a fast tour kpeter@1204: /// construction heuristic (e.g. the InsertionTsp algorithm). kpeter@1201: /// kpeter@1201: /// \tparam CM Type of the cost map. f4c3@1199: template kpeter@1201: class Opt2Tsp kpeter@1201: { kpeter@1201: public: kpeter@1201: kpeter@1201: /// Type of the cost map kpeter@1201: typedef CM CostMap; kpeter@1201: /// Type of the edge costs kpeter@1201: typedef typename CM::Value Cost; kpeter@1201: f4c3@1199: private: kpeter@1201: f4c3@1199: GRAPH_TYPEDEFS(FullGraph); f4c3@1199: kpeter@1201: const FullGraph &_gr; kpeter@1201: const CostMap &_cost; kpeter@1201: Cost _sum; kpeter@1201: std::vector _plist; kpeter@1201: std::vector _path; kpeter@1201: f4c3@1199: public: kpeter@1201: kpeter@1201: /// \brief Constructor kpeter@1201: /// kpeter@1201: /// Constructor. kpeter@1201: /// \param gr The \ref FullGraph "full graph" the algorithm runs on. kpeter@1201: /// \param cost The cost map. kpeter@1201: Opt2Tsp(const FullGraph &gr, const CostMap &cost) kpeter@1201: : _gr(gr), _cost(cost) {} kpeter@1201: kpeter@1201: /// \name Execution Control kpeter@1201: /// @{ kpeter@1201: kpeter@1201: /// \brief Runs the algorithm from scratch. kpeter@1201: /// kpeter@1201: /// This function runs the algorithm starting from the tour that is kpeter@1201: /// determined by the node ID sequence. kpeter@1201: /// kpeter@1201: /// \return The total cost of the found tour. kpeter@1201: Cost run() { kpeter@1201: _path.clear(); kpeter@1201: kpeter@1201: if (_gr.nodeNum() == 0) return _sum = 0; kpeter@1201: else if (_gr.nodeNum() == 1) { kpeter@1201: _path.push_back(_gr(0)); kpeter@1201: return _sum = 0; f4c3@1199: } kpeter@1201: else if (_gr.nodeNum() == 2) { kpeter@1201: _path.push_back(_gr(0)); kpeter@1201: _path.push_back(_gr(1)); kpeter@1201: return _sum = 2 * _cost[_gr.edge(_gr(0), _gr(1))]; kpeter@1201: } f4c3@1199: kpeter@1201: _plist.resize(2*_gr.nodeNum()); kpeter@1201: for (int i = 1; i < _gr.nodeNum()-1; ++i) { kpeter@1201: _plist[2*i] = i-1; kpeter@1201: _plist[2*i+1] = i+1; f4c3@1199: } kpeter@1201: _plist[0] = _gr.nodeNum()-1; kpeter@1201: _plist[1] = 1; kpeter@1201: _plist[2*_gr.nodeNum()-2] = _gr.nodeNum()-2; kpeter@1201: _plist[2*_gr.nodeNum()-1] = 0; kpeter@1201: kpeter@1201: return start(); f4c3@1199: } f4c3@1199: kpeter@1202: /// \brief Runs the algorithm starting from the given tour. kpeter@1201: /// kpeter@1201: /// This function runs the algorithm starting from the given tour. kpeter@1201: /// kpeter@1201: /// \param tour The tour as a path structure. It must be a kpeter@1201: /// \ref checkPath() "valid path" containing excactly n arcs. kpeter@1201: /// kpeter@1201: /// \return The total cost of the found tour. kpeter@1201: template kpeter@1201: Cost run(const Path& tour) { kpeter@1201: _path.clear(); kpeter@1201: kpeter@1201: if (_gr.nodeNum() == 0) return _sum = 0; kpeter@1201: else if (_gr.nodeNum() == 1) { kpeter@1201: _path.push_back(_gr(0)); kpeter@1201: return _sum = 0; kpeter@1201: } kpeter@1201: else if (_gr.nodeNum() == 2) { kpeter@1201: _path.push_back(_gr(0)); kpeter@1201: _path.push_back(_gr(1)); kpeter@1201: return _sum = 2 * _cost[_gr.edge(_gr(0), _gr(1))]; kpeter@1201: } kpeter@1201: kpeter@1201: _plist.resize(2*_gr.nodeNum()); kpeter@1201: typename Path::ArcIt it(tour); kpeter@1201: int first = _gr.id(_gr.source(it)), kpeter@1201: prev = first, kpeter@1201: curr = _gr.id(_gr.target(it)), kpeter@1201: next = -1; kpeter@1201: _plist[2*first+1] = curr; kpeter@1201: for (++it; it != INVALID; ++it) { kpeter@1201: next = _gr.id(_gr.target(it)); kpeter@1201: _plist[2*curr] = prev; kpeter@1201: _plist[2*curr+1] = next; kpeter@1201: prev = curr; kpeter@1201: curr = next; kpeter@1201: } kpeter@1201: _plist[2*first] = prev; kpeter@1201: kpeter@1201: return start(); kpeter@1201: } kpeter@1201: kpeter@1202: /// \brief Runs the algorithm starting from the given tour. kpeter@1201: /// kpeter@1202: /// This function runs the algorithm starting from the given tour kpeter@1202: /// (node sequence). kpeter@1201: /// kpeter@1202: /// \param tour A vector that stores all Nodes of the graph kpeter@1202: /// in the desired order. kpeter@1201: /// kpeter@1201: /// \return The total cost of the found tour. kpeter@1202: Cost run(const std::vector& tour) { kpeter@1201: _path.clear(); kpeter@1201: kpeter@1201: if (_gr.nodeNum() == 0) return _sum = 0; kpeter@1201: else if (_gr.nodeNum() == 1) { kpeter@1201: _path.push_back(_gr(0)); kpeter@1201: return _sum = 0; kpeter@1201: } kpeter@1201: else if (_gr.nodeNum() == 2) { kpeter@1201: _path.push_back(_gr(0)); kpeter@1201: _path.push_back(_gr(1)); kpeter@1201: return _sum = 2 * _cost[_gr.edge(_gr(0), _gr(1))]; kpeter@1201: } kpeter@1201: kpeter@1201: _plist.resize(2*_gr.nodeNum()); kpeter@1202: typename std::vector::const_iterator it = tour.begin(); kpeter@1201: int first = _gr.id(*it), kpeter@1201: prev = first, kpeter@1201: curr = _gr.id(*(++it)), kpeter@1201: next = -1; kpeter@1201: _plist[2*first+1] = curr; kpeter@1201: for (++it; it != tour.end(); ++it) { kpeter@1201: next = _gr.id(*it); kpeter@1201: _plist[2*curr] = prev; kpeter@1201: _plist[2*curr+1] = next; kpeter@1201: prev = curr; kpeter@1201: curr = next; kpeter@1201: } kpeter@1201: _plist[2*first] = curr; kpeter@1201: _plist[2*curr] = prev; kpeter@1201: _plist[2*curr+1] = first; kpeter@1201: kpeter@1201: return start(); kpeter@1201: } kpeter@1201: kpeter@1201: /// @} kpeter@1201: kpeter@1201: /// \name Query Functions kpeter@1201: /// @{ kpeter@1201: kpeter@1201: /// \brief The total cost of the found tour. kpeter@1201: /// kpeter@1201: /// This function returns the total cost of the found tour. kpeter@1201: /// kpeter@1201: /// \pre run() must be called before using this function. kpeter@1201: Cost tourCost() const { kpeter@1201: return _sum; kpeter@1201: } kpeter@1201: kpeter@1201: /// \brief Returns a const reference to the node sequence of the kpeter@1201: /// found tour. kpeter@1201: /// kpeter@1202: /// This function returns a const reference to a vector kpeter@1201: /// that stores the node sequence of the found tour. kpeter@1201: /// kpeter@1201: /// \pre run() must be called before using this function. kpeter@1201: const std::vector& tourNodes() const { kpeter@1201: return _path; kpeter@1201: } kpeter@1201: kpeter@1201: /// \brief Gives back the node sequence of the found tour. kpeter@1201: /// kpeter@1201: /// This function copies the node sequence of the found tour into kpeter@1205: /// an STL container through the given output iterator. The kpeter@1205: /// value_type of the container must be FullGraph::Node. kpeter@1205: /// For example, kpeter@1205: /// \code kpeter@1205: /// std::vector nodes(countNodes(graph)); kpeter@1205: /// tsp.tourNodes(nodes.begin()); kpeter@1205: /// \endcode kpeter@1205: /// or kpeter@1205: /// \code kpeter@1205: /// std::list nodes; kpeter@1205: /// tsp.tourNodes(std::back_inserter(nodes)); kpeter@1205: /// \endcode kpeter@1201: /// kpeter@1201: /// \pre run() must be called before using this function. kpeter@1205: template kpeter@1205: void tourNodes(Iterator out) const { kpeter@1205: std::copy(_path.begin(), _path.end(), out); kpeter@1201: } kpeter@1201: kpeter@1201: /// \brief Gives back the found tour as a path. kpeter@1201: /// kpeter@1201: /// This function copies the found tour as a list of arcs/edges into alpar@1250: /// the given \ref lemon::concepts::Path "path structure". kpeter@1201: /// kpeter@1201: /// \pre run() must be called before using this function. kpeter@1201: template kpeter@1201: void tour(Path &path) const { kpeter@1201: path.clear(); kpeter@1201: for (int i = 0; i < int(_path.size()) - 1; ++i) { kpeter@1201: path.addBack(_gr.arc(_path[i], _path[i+1])); kpeter@1201: } kpeter@1201: if (int(_path.size()) >= 2) { kpeter@1201: path.addBack(_gr.arc(_path.back(), _path.front())); kpeter@1201: } kpeter@1201: } kpeter@1201: kpeter@1201: /// @} kpeter@1201: f4c3@1199: private: kpeter@1201: kpeter@1201: // Iterator class for the linked list storage of the tour kpeter@1201: class PathListIt { f4c3@1199: public: kpeter@1201: PathListIt(const std::vector &pl, int i=0) kpeter@1201: : plist(&pl), act(i), last(pl[2*act]) {} kpeter@1201: PathListIt(const std::vector &pl, int i, int l) kpeter@1201: : plist(&pl), act(i), last(l) {} f4c3@1199: kpeter@1201: int nextIndex() const { kpeter@1201: return (*plist)[2*act] == last ? 2*act+1 : 2*act; f4c3@1199: } kpeter@1201: kpeter@1201: int prevIndex() const { kpeter@1201: return (*plist)[2*act] == last ? 2*act : 2*act+1; f4c3@1199: } kpeter@1201: f4c3@1199: int next() const { kpeter@1201: int x = (*plist)[2*act]; kpeter@1201: return x == last ? (*plist)[2*act+1] : x; f4c3@1199: } f4c3@1199: f4c3@1199: int prev() const { kpeter@1201: return last; f4c3@1199: } kpeter@1201: kpeter@1201: PathListIt& operator++() { f4c3@1199: int tmp = act; f4c3@1199: act = next(); f4c3@1199: last = tmp; f4c3@1199: return *this; f4c3@1199: } kpeter@1201: f4c3@1199: operator int() const { f4c3@1199: return act; f4c3@1199: } kpeter@1201: f4c3@1199: private: kpeter@1201: const std::vector *plist; f4c3@1199: int act; f4c3@1199: int last; f4c3@1199: }; f4c3@1199: kpeter@1201: // Checks and applies 2-opt move (if it improves the tour) kpeter@1201: bool checkOpt2(const PathListIt& i, const PathListIt& j) { kpeter@1201: Node u = _gr.nodeFromId(i), kpeter@1201: un = _gr.nodeFromId(i.next()), kpeter@1201: v = _gr.nodeFromId(j), kpeter@1201: vn = _gr.nodeFromId(j.next()); f4c3@1199: kpeter@1201: if (_cost[_gr.edge(u, un)] + _cost[_gr.edge(v, vn)] > kpeter@1201: _cost[_gr.edge(u, v)] + _cost[_gr.edge(un, vn)]) kpeter@1201: { kpeter@1201: _plist[PathListIt(_plist, i.next(), i).prevIndex()] = j.next(); kpeter@1201: _plist[PathListIt(_plist, j.next(), j).prevIndex()] = i.next(); f4c3@1199: kpeter@1201: _plist[i.nextIndex()] = j; kpeter@1201: _plist[j.nextIndex()] = i; f4c3@1199: kpeter@1201: return true; f4c3@1199: } kpeter@1201: f4c3@1199: return false; kpeter@1201: } f4c3@1199: kpeter@1201: // Executes the algorithm from the initial tour kpeter@1201: Cost start() { f4c3@1199: kpeter@1201: restart_search: kpeter@1201: for (PathListIt i(_plist); true; ++i) { kpeter@1201: PathListIt j = i; kpeter@1201: if (++j == 0 || ++j == 0) break; kpeter@1201: for (; j != 0 && j != i.prev(); ++j) { kpeter@1201: if (checkOpt2(i, j)) kpeter@1201: goto restart_search; f4c3@1199: } f4c3@1199: } f4c3@1199: kpeter@1201: PathListIt i(_plist); kpeter@1201: _path.push_back(_gr.nodeFromId(i)); kpeter@1201: for (++i; i != 0; ++i) kpeter@1201: _path.push_back(_gr.nodeFromId(i)); f4c3@1199: kpeter@1201: _sum = _cost[_gr.edge(_path.back(), _path.front())]; kpeter@1201: for (int i = 0; i < int(_path.size())-1; ++i) { kpeter@1201: _sum += _cost[_gr.edge(_path[i], _path[i+1])]; kpeter@1201: } f4c3@1199: f4c3@1199: return _sum; f4c3@1199: } f4c3@1199: f4c3@1199: }; f4c3@1199: f4c3@1199: }; // namespace lemon f4c3@1199: f4c3@1199: #endif