COIN-OR::LEMON - Graph Library

source: lemon/lemon/greedy_tsp.h @ 1202:ef200e268af2

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

Unifications and improvements in TSP algorithms (#386)

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