lemon/greedy_tsp.h
author Peter Kovacs <kpeter@inf.elte.hu>
Sat, 08 Jan 2011 22:51:16 +0100
changeset 1033 9a51db038228
parent 1031 ae0b056593a7
child 1034 ef200e268af2
permissions -rw-r--r--
Document and greatly improve TSP algorithms (#386)

- Add LEMON headers.
- Add Doxygen doc for all classes and their members.
- Clarify and unify the public API of the algorithms.
- Various small improvements in the implementations to make
them clearer and faster.
- Avoid using adaptors in ChristofidesTsp.
     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-2010
     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   /// \brief Greedy algorithm for symmetric TSP.
    34   ///
    35   /// GreedyTsp implements the greedy heuristic for solving
    36   /// symmetric \ref tsp "TSP".
    37   ///
    38   /// This algorithm is quite similar to the \ref NearestNeighborTsp
    39   /// "nearest neighbor" heuristic, but it maintains a set of disjoint paths.
    40   /// At each step, the shortest possible edge is added to these paths
    41   /// as long as it does not create a cycle of less than n edges and it does
    42   /// not increase the degree of any node above two.
    43   ///
    44   /// This method runs in O(n<sup>2</sup>log(n)) time.
    45   /// It quickly finds an effectively short tour for most TSP
    46   /// instances, but in special cases, it could yield a really bad
    47   /// (or even the worst) solution.
    48   ///
    49   /// \tparam CM Type of the cost map.
    50   template <typename CM>
    51   class GreedyTsp
    52   {
    53     public:
    54 
    55       /// Type of the cost map
    56       typedef CM CostMap;
    57       /// Type of the edge costs
    58       typedef typename CM::Value Cost;
    59 
    60     private:
    61 
    62       GRAPH_TYPEDEFS(FullGraph);
    63 
    64       const FullGraph &_gr;
    65       const CostMap &_cost;
    66       Cost _sum;
    67       std::vector<Node> _path;
    68       
    69     private:
    70     
    71       // Functor class to compare edges by their costs
    72       class EdgeComp {
    73       private:
    74         const CostMap &_cost;
    75 
    76       public:
    77         EdgeComp(const CostMap &cost) : _cost(cost) {}
    78 
    79         bool operator()(const Edge &a, const Edge &b) const {
    80           return _cost[a] < _cost[b];
    81         }
    82       };
    83 
    84     public:
    85 
    86       /// \brief Constructor
    87       ///
    88       /// Constructor.
    89       /// \param gr The \ref FullGraph "full graph" the algorithm runs on.
    90       /// \param cost The cost map.
    91       GreedyTsp(const FullGraph &gr, const CostMap &cost)
    92         : _gr(gr), _cost(cost) {}
    93 
    94       /// \name Execution Control
    95       /// @{
    96 
    97       /// \brief Runs the algorithm.
    98       ///
    99       /// This function runs the algorithm.
   100       ///
   101       /// \return The total cost of the found tour.
   102       Cost run() {
   103         _path.clear();
   104 
   105         if (_gr.nodeNum() == 0) return _sum = 0;
   106         else if (_gr.nodeNum() == 1) {
   107           _path.push_back(_gr(0));
   108           return _sum = 0;
   109         }
   110 
   111         std::vector<int> plist;
   112         plist.resize(_gr.nodeNum()*2, -1);
   113 
   114         std::vector<Edge> sorted_edges;
   115         sorted_edges.reserve(_gr.edgeNum());
   116         for (EdgeIt e(_gr); e != INVALID; ++e)
   117           sorted_edges.push_back(e);
   118         std::sort(sorted_edges.begin(), sorted_edges.end(), EdgeComp(_cost));
   119 
   120         FullGraph::NodeMap<int> item_int_map(_gr);
   121         UnionFind<FullGraph::NodeMap<int> > union_find(item_int_map);
   122         for (NodeIt n(_gr); n != INVALID; ++n)
   123           union_find.insert(n);
   124 
   125         FullGraph::NodeMap<int> degree(_gr, 0);
   126 
   127         int nodesNum = 0, i = 0;
   128         while (nodesNum != _gr.nodeNum()-1) {
   129           Edge e = sorted_edges[i++];
   130           Node u = _gr.u(e),
   131                v = _gr.v(e);
   132 
   133           if (degree[u] <= 1 && degree[v] <= 1) {
   134             if (union_find.join(u, v)) {
   135               const int uid = _gr.id(u),
   136                         vid = _gr.id(v);
   137 
   138               plist[uid*2 + degree[u]] = vid;
   139               plist[vid*2 + degree[v]] = uid;
   140 
   141               ++degree[u];
   142               ++degree[v];
   143               ++nodesNum;
   144             }
   145           }
   146         }
   147 
   148         for (int i=0, n=-1; i<_gr.nodeNum()*2; ++i) {
   149           if (plist[i] == -1) {
   150             if (n==-1) {
   151               n = i;
   152             } else {
   153               plist[n] = i/2;
   154               plist[i] = n/2;
   155               break;
   156             }
   157           }
   158         }
   159 
   160         for (int i=0, next=0, last=-1; i!=_gr.nodeNum(); ++i) {
   161           _path.push_back(_gr.nodeFromId(next));
   162           if (plist[2*next] != last) {
   163             last = next;
   164             next = plist[2*next];
   165           } else {
   166             last = next;
   167             next = plist[2*next+1];
   168           }
   169         }
   170 
   171         _sum = _cost[_gr.edge(_path.back(), _path.front())];
   172         for (int i = 0; i < int(_path.size())-1; ++i) {
   173           _sum += _cost[_gr.edge(_path[i], _path[i+1])];
   174         }
   175 
   176         return _sum;
   177       }
   178 
   179       /// @}
   180 
   181       /// \name Query Functions
   182       /// @{
   183 
   184       /// \brief The total cost of the found tour.
   185       ///
   186       /// This function returns the total cost of the found tour.
   187       ///
   188       /// \pre run() must be called before using this function.
   189       Cost tourCost() const {
   190         return _sum;
   191       }
   192 
   193       /// \brief Returns a const reference to the node sequence of the
   194       /// found tour.
   195       ///
   196       /// This function returns a const reference to the internal structure
   197       /// that stores the node sequence of the found tour.
   198       ///
   199       /// \pre run() must be called before using this function.
   200       const std::vector<Node>& tourNodes() const {
   201         return _path;
   202       }
   203 
   204       /// \brief Gives back the node sequence of the found tour.
   205       ///
   206       /// This function copies the node sequence of the found tour into
   207       /// the given standard container.
   208       ///
   209       /// \pre run() must be called before using this function.
   210       template <typename Container>
   211       void tourNodes(Container &container) const {
   212         container.assign(_path.begin(), _path.end());
   213       }
   214 
   215       /// \brief Gives back the found tour as a path.
   216       ///
   217       /// This function copies the found tour as a list of arcs/edges into
   218       /// the given \ref concept::Path "path structure".
   219       ///
   220       /// \pre run() must be called before using this function.
   221       template <typename Path>
   222       void tour(Path &path) const {
   223         path.clear();
   224         for (int i = 0; i < int(_path.size()) - 1; ++i) {
   225           path.addBack(_gr.arc(_path[i], _path[i+1]));
   226         }
   227         if (int(_path.size()) >= 2) {
   228           path.addBack(_gr.arc(_path.back(), _path.front()));
   229         }
   230       }
   231 
   232       /// @}
   233 
   234   };
   235 
   236 }; // namespace lemon
   237 
   238 #endif