lemon/greedy_tsp.h
author Alpar Juttner <alpar@cs.elte.hu>
Wed, 29 Jul 2020 14:56:10 +0200
changeset 1433 a278d16bd2d0
parent 1250 97d978243703
permissions -rw-r--r--
Fix clang compilation issue (#634)
     1 /* -*- mode: C++; indent-tabs-mode: nil; -*-
     2  *
     3  * This file is a part of LEMON, a generic C++ optimization library.
     4  *
     5  * Copyright (C) 2003-2013
     6  * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport
     7  * (Egervary Research Group on Combinatorial Optimization, EGRES).
     8  *
     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.
    12  *
    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
    15  * purpose.
    16  *
    17  */
    18 
    19 #ifndef LEMON_GREEDY_TSP_H
    20 #define LEMON_GREEDY_TSP_H
    21 
    22 /// \ingroup tsp
    23 /// \file
    24 /// \brief Greedy algorithm for symmetric TSP
    25 
    26 #include <vector>
    27 #include <algorithm>
    28 #include <lemon/full_graph.h>
    29 #include <lemon/unionfind.h>
    30 
    31 namespace lemon {
    32 
    33   /// \ingroup tsp
    34   ///
    35   /// \brief Greedy algorithm for symmetric TSP.
    36   ///
    37   /// GreedyTsp implements the greedy heuristic for solving
    38   /// symmetric \ref tsp "TSP".
    39   ///
    40   /// This algorithm is quite similar to the \ref NearestNeighborTsp
    41   /// "nearest neighbor" heuristic, but it maintains a set of disjoint paths.
    42   /// At each step, the shortest possible edge is added to these paths
    43   /// as long as it does not create a cycle of less than n edges and it does
    44   /// not increase the degree of any node above two.
    45   ///
    46   /// This method runs in O(n<sup>2</sup>) time.
    47   /// It quickly finds a relatively short tour for most TSP instances,
    48   /// but it could also yield a really bad (or even the worst) solution
    49   /// in special cases.
    50   ///
    51   /// \tparam CM Type of the cost map.
    52   template <typename CM>
    53   class GreedyTsp
    54   {
    55     public:
    56 
    57       /// Type of the cost map
    58       typedef CM CostMap;
    59       /// Type of the edge costs
    60       typedef typename CM::Value Cost;
    61 
    62     private:
    63 
    64       GRAPH_TYPEDEFS(FullGraph);
    65 
    66       const FullGraph &_gr;
    67       const CostMap &_cost;
    68       Cost _sum;
    69       std::vector<Node> _path;
    70 
    71     private:
    72 
    73       // Functor class to compare edges by their costs
    74       class EdgeComp {
    75       private:
    76         const CostMap &_cost;
    77 
    78       public:
    79         EdgeComp(const CostMap &cost) : _cost(cost) {}
    80 
    81         bool operator()(const Edge &a, const Edge &b) const {
    82           return _cost[a] < _cost[b];
    83         }
    84       };
    85 
    86     public:
    87 
    88       /// \brief Constructor
    89       ///
    90       /// Constructor.
    91       /// \param gr The \ref FullGraph "full graph" the algorithm runs on.
    92       /// \param cost The cost map.
    93       GreedyTsp(const FullGraph &gr, const CostMap &cost)
    94         : _gr(gr), _cost(cost) {}
    95 
    96       /// \name Execution Control
    97       /// @{
    98 
    99       /// \brief Runs the algorithm.
   100       ///
   101       /// This function runs the algorithm.
   102       ///
   103       /// \return The total cost of the found tour.
   104       Cost run() {
   105         _path.clear();
   106 
   107         if (_gr.nodeNum() == 0) return _sum = 0;
   108         else if (_gr.nodeNum() == 1) {
   109           _path.push_back(_gr(0));
   110           return _sum = 0;
   111         }
   112 
   113         std::vector<int> plist;
   114         plist.resize(_gr.nodeNum()*2, -1);
   115 
   116         std::vector<Edge> sorted_edges;
   117         sorted_edges.reserve(_gr.edgeNum());
   118         for (EdgeIt e(_gr); e != INVALID; ++e)
   119           sorted_edges.push_back(e);
   120         std::sort(sorted_edges.begin(), sorted_edges.end(), EdgeComp(_cost));
   121 
   122         FullGraph::NodeMap<int> item_int_map(_gr);
   123         UnionFind<FullGraph::NodeMap<int> > union_find(item_int_map);
   124         for (NodeIt n(_gr); n != INVALID; ++n)
   125           union_find.insert(n);
   126 
   127         FullGraph::NodeMap<int> degree(_gr, 0);
   128 
   129         int nodesNum = 0, i = 0;
   130         while (nodesNum != _gr.nodeNum()-1) {
   131           Edge e = sorted_edges[i++];
   132           Node u = _gr.u(e),
   133                v = _gr.v(e);
   134 
   135           if (degree[u] <= 1 && degree[v] <= 1) {
   136             if (union_find.join(u, v)) {
   137               const int uid = _gr.id(u),
   138                         vid = _gr.id(v);
   139 
   140               plist[uid*2 + degree[u]] = vid;
   141               plist[vid*2 + degree[v]] = uid;
   142 
   143               ++degree[u];
   144               ++degree[v];
   145               ++nodesNum;
   146             }
   147           }
   148         }
   149 
   150         for (int i=0, n=-1; i<_gr.nodeNum()*2; ++i) {
   151           if (plist[i] == -1) {
   152             if (n==-1) {
   153               n = i;
   154             } else {
   155               plist[n] = i/2;
   156               plist[i] = n/2;
   157               break;
   158             }
   159           }
   160         }
   161 
   162         for (int i=0, next=0, last=-1; i!=_gr.nodeNum(); ++i) {
   163           _path.push_back(_gr.nodeFromId(next));
   164           if (plist[2*next] != last) {
   165             last = next;
   166             next = plist[2*next];
   167           } else {
   168             last = next;
   169             next = plist[2*next+1];
   170           }
   171         }
   172 
   173         _sum = _cost[_gr.edge(_path.back(), _path.front())];
   174         for (int i = 0; i < int(_path.size())-1; ++i) {
   175           _sum += _cost[_gr.edge(_path[i], _path[i+1])];
   176         }
   177 
   178         return _sum;
   179       }
   180 
   181       /// @}
   182 
   183       /// \name Query Functions
   184       /// @{
   185 
   186       /// \brief The total cost of the found tour.
   187       ///
   188       /// This function returns the total cost of the found tour.
   189       ///
   190       /// \pre run() must be called before using this function.
   191       Cost tourCost() const {
   192         return _sum;
   193       }
   194 
   195       /// \brief Returns a const reference to the node sequence of the
   196       /// found tour.
   197       ///
   198       /// This function returns a const reference to a vector
   199       /// that stores the node sequence of the found tour.
   200       ///
   201       /// \pre run() must be called before using this function.
   202       const std::vector<Node>& tourNodes() const {
   203         return _path;
   204       }
   205 
   206       /// \brief Gives back the node sequence of the found tour.
   207       ///
   208       /// This function copies the node sequence of the found tour into
   209       /// an STL container through the given output iterator. The
   210       /// <tt>value_type</tt> of the container must be <tt>FullGraph::Node</tt>.
   211       /// For example,
   212       /// \code
   213       /// std::vector<FullGraph::Node> nodes(countNodes(graph));
   214       /// tsp.tourNodes(nodes.begin());
   215       /// \endcode
   216       /// or
   217       /// \code
   218       /// std::list<FullGraph::Node> nodes;
   219       /// tsp.tourNodes(std::back_inserter(nodes));
   220       /// \endcode
   221       ///
   222       /// \pre run() must be called before using this function.
   223       template <typename Iterator>
   224       void tourNodes(Iterator out) const {
   225         std::copy(_path.begin(), _path.end(), out);
   226       }
   227 
   228       /// \brief Gives back the found tour as a path.
   229       ///
   230       /// This function copies the found tour as a list of arcs/edges into
   231       /// the given \ref lemon::concepts::Path "path structure".
   232       ///
   233       /// \pre run() must be called before using this function.
   234       template <typename Path>
   235       void tour(Path &path) const {
   236         path.clear();
   237         for (int i = 0; i < int(_path.size()) - 1; ++i) {
   238           path.addBack(_gr.arc(_path[i], _path[i+1]));
   239         }
   240         if (int(_path.size()) >= 2) {
   241           path.addBack(_gr.arc(_path.back(), _path.front()));
   242         }
   243       }
   244 
   245       /// @}
   246 
   247   };
   248 
   249 }; // namespace lemon
   250 
   251 #endif