COIN-OR::LEMON - Graph Library

source: lemon/lemon/greedy_tsp.h @ 1201:9a51db038228

Last change on this file since 1201:9a51db038228 was 1201:9a51db038228, checked in by Peter Kovacs <kpeter@…>, 13 years ago

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?.
File size: 6.6 KB
RevLine 
[1201]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
[1199]19#ifndef LEMON_GREEDY_TSP_H
20#define LEMON_GREEDY_TSP_H
21
[1201]22/// \ingroup tsp
23/// \file
24/// \brief Greedy algorithm for symmetric TSP
25
26#include <vector>
27#include <algorithm>
[1199]28#include <lemon/full_graph.h>
29#include <lemon/unionfind.h>
30
31namespace lemon {
32
[1201]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:
[1199]54
[1201]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;
[1199]68     
[1201]69    private:
70   
71      // Functor class to compare edges by their costs
72      class EdgeComp {
73      private:
74        const CostMap &_cost;
75
[1199]76      public:
[1201]77        EdgeComp(const CostMap &cost) : _cost(cost) {}
78
79        bool operator()(const Edge &a, const Edge &b) const {
80          return _cost[a] < _cost[b];
[1199]81        }
[1201]82      };
[1199]83
[1201]84    public:
[1199]85
[1201]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) {}
[1199]93
[1201]94      /// \name Execution Control
95      /// @{
[1199]96
[1201]97      /// \brief Runs the algorithm.
98      ///
99      /// This function runs the algorithm.
100      ///
101      /// \return The total cost of the found tour.
[1199]102      Cost run() {
[1201]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;
[1199]115        sorted_edges.reserve(_gr.edgeNum());
[1201]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));
[1199]119
[1201]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);
[1199]124
125        FullGraph::NodeMap<int> degree(_gr, 0);
126
127        int nodesNum = 0, i = 0;
[1201]128        while (nodesNum != _gr.nodeNum()-1) {
129          Edge e = sorted_edges[i++];
130          Node u = _gr.u(e),
131               v = _gr.v(e);
[1199]132
[1201]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
[1199]141              ++degree[u];
142              ++degree[v];
143              ++nodesNum;
144            }
145          }
146        }
147
148        for (int i=0, n=-1; i<_gr.nodeNum()*2; ++i) {
[1201]149          if (plist[i] == -1) {
[1199]150            if (n==-1) {
151              n = i;
152            } else {
[1201]153              plist[n] = i/2;
154              plist[i] = n/2;
[1199]155              break;
156            }
157          }
158        }
159
[1201]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];
[1199]165          } else {
[1201]166            last = next;
167            next = plist[2*next+1];
[1199]168          }
169        }
170
[1201]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        }
[1199]175
176        return _sum;
177      }
178
[1201]179      /// @}
[1199]180
[1201]181      /// \name Query Functions
182      /// @{
[1199]183
[1201]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 {
[1199]190        return _sum;
191      }
192
[1201]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
[1199]234  };
235
236}; // namespace lemon
237
238#endif
Note: See TracBrowser for help on using the repository browser.