1 /* -*- mode: C++; indent-tabs-mode: nil; -*-
3 * This file is a part of LEMON, a generic C++ optimization library.
5 * Copyright (C) 2003-2010
6 * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport
7 * (Egervary Research Group on Combinatorial Optimization, EGRES).
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.
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
19 #ifndef LEMON_OPT2_TSP_H
20 #define LEMON_OPT2_TSP_H
24 /// \brief 2-opt algorithm for symmetric TSP.
27 #include <lemon/full_graph.h>
33 /// \brief 2-opt algorithm for symmetric TSP.
35 /// Opt2Tsp implements the 2-opt heuristic for solving
36 /// symmetric \ref tsp "TSP".
38 /// This algorithm starts with an initial tour and iteratively improves it.
39 /// At each step, it removes two edges and the reconnects the created two
40 /// paths in the other way if the resulting tour is shorter.
41 /// The algorithm finishes when no such 2-opt move can be applied, and so
42 /// the tour is 2-optimal.
44 /// If no starting tour is given to the \ref run() function, then the
45 /// algorithm uses the node sequence determined by the node IDs.
46 /// Oherwise, it starts with the given tour.
48 /// This is a rather slow but effective method.
49 /// Its typical usage is the improvement of the result of a fast tour
50 /// construction heuristic (e.g. the InsertionTsp algorithm).
52 /// \tparam CM Type of the cost map.
53 template <typename CM>
58 /// Type of the cost map
60 /// Type of the edge costs
61 typedef typename CM::Value Cost;
65 GRAPH_TYPEDEFS(FullGraph);
70 std::vector<int> _plist;
71 std::vector<Node> _path;
75 /// \brief Constructor
78 /// \param gr The \ref FullGraph "full graph" the algorithm runs on.
79 /// \param cost The cost map.
80 Opt2Tsp(const FullGraph &gr, const CostMap &cost)
81 : _gr(gr), _cost(cost) {}
83 /// \name Execution Control
86 /// \brief Runs the algorithm from scratch.
88 /// This function runs the algorithm starting from the tour that is
89 /// determined by the node ID sequence.
91 /// \return The total cost of the found tour.
95 if (_gr.nodeNum() == 0) return _sum = 0;
96 else if (_gr.nodeNum() == 1) {
97 _path.push_back(_gr(0));
100 else if (_gr.nodeNum() == 2) {
101 _path.push_back(_gr(0));
102 _path.push_back(_gr(1));
103 return _sum = 2 * _cost[_gr.edge(_gr(0), _gr(1))];
106 _plist.resize(2*_gr.nodeNum());
107 for (int i = 1; i < _gr.nodeNum()-1; ++i) {
111 _plist[0] = _gr.nodeNum()-1;
113 _plist[2*_gr.nodeNum()-2] = _gr.nodeNum()-2;
114 _plist[2*_gr.nodeNum()-1] = 0;
119 /// \brief Runs the algorithm starting from the given tour.
121 /// This function runs the algorithm starting from the given tour.
123 /// \param tour The tour as a path structure. It must be a
124 /// \ref checkPath() "valid path" containing excactly n arcs.
126 /// \return The total cost of the found tour.
127 template <typename Path>
128 Cost run(const Path& tour) {
131 if (_gr.nodeNum() == 0) return _sum = 0;
132 else if (_gr.nodeNum() == 1) {
133 _path.push_back(_gr(0));
136 else if (_gr.nodeNum() == 2) {
137 _path.push_back(_gr(0));
138 _path.push_back(_gr(1));
139 return _sum = 2 * _cost[_gr.edge(_gr(0), _gr(1))];
142 _plist.resize(2*_gr.nodeNum());
143 typename Path::ArcIt it(tour);
144 int first = _gr.id(_gr.source(it)),
146 curr = _gr.id(_gr.target(it)),
148 _plist[2*first+1] = curr;
149 for (++it; it != INVALID; ++it) {
150 next = _gr.id(_gr.target(it));
151 _plist[2*curr] = prev;
152 _plist[2*curr+1] = next;
156 _plist[2*first] = prev;
161 /// \brief Runs the algorithm starting from the given tour.
163 /// This function runs the algorithm starting from the given tour
166 /// \param tour A vector that stores all <tt>Node</tt>s of the graph
167 /// in the desired order.
169 /// \return The total cost of the found tour.
170 Cost run(const std::vector<Node>& tour) {
173 if (_gr.nodeNum() == 0) return _sum = 0;
174 else if (_gr.nodeNum() == 1) {
175 _path.push_back(_gr(0));
178 else if (_gr.nodeNum() == 2) {
179 _path.push_back(_gr(0));
180 _path.push_back(_gr(1));
181 return _sum = 2 * _cost[_gr.edge(_gr(0), _gr(1))];
184 _plist.resize(2*_gr.nodeNum());
185 typename std::vector<Node>::const_iterator it = tour.begin();
186 int first = _gr.id(*it),
188 curr = _gr.id(*(++it)),
190 _plist[2*first+1] = curr;
191 for (++it; it != tour.end(); ++it) {
193 _plist[2*curr] = prev;
194 _plist[2*curr+1] = next;
198 _plist[2*first] = curr;
199 _plist[2*curr] = prev;
200 _plist[2*curr+1] = first;
207 /// \name Query Functions
210 /// \brief The total cost of the found tour.
212 /// This function returns the total cost of the found tour.
214 /// \pre run() must be called before using this function.
215 Cost tourCost() const {
219 /// \brief Returns a const reference to the node sequence of the
222 /// This function returns a const reference to a vector
223 /// that stores the node sequence of the found tour.
225 /// \pre run() must be called before using this function.
226 const std::vector<Node>& tourNodes() const {
230 /// \brief Gives back the node sequence of the found tour.
232 /// This function copies the node sequence of the found tour into
233 /// an STL container through the given output iterator. The
234 /// <tt>value_type</tt> of the container must be <tt>FullGraph::Node</tt>.
237 /// std::vector<FullGraph::Node> nodes(countNodes(graph));
238 /// tsp.tourNodes(nodes.begin());
242 /// std::list<FullGraph::Node> nodes;
243 /// tsp.tourNodes(std::back_inserter(nodes));
246 /// \pre run() must be called before using this function.
247 template <typename Iterator>
248 void tourNodes(Iterator out) const {
249 std::copy(_path.begin(), _path.end(), out);
252 /// \brief Gives back the found tour as a path.
254 /// This function copies the found tour as a list of arcs/edges into
255 /// the given \ref lemon::concepts::Path "path structure".
257 /// \pre run() must be called before using this function.
258 template <typename Path>
259 void tour(Path &path) const {
261 for (int i = 0; i < int(_path.size()) - 1; ++i) {
262 path.addBack(_gr.arc(_path[i], _path[i+1]));
264 if (int(_path.size()) >= 2) {
265 path.addBack(_gr.arc(_path.back(), _path.front()));
273 // Iterator class for the linked list storage of the tour
276 PathListIt(const std::vector<int> &pl, int i=0)
277 : plist(&pl), act(i), last(pl[2*act]) {}
278 PathListIt(const std::vector<int> &pl, int i, int l)
279 : plist(&pl), act(i), last(l) {}
281 int nextIndex() const {
282 return (*plist)[2*act] == last ? 2*act+1 : 2*act;
285 int prevIndex() const {
286 return (*plist)[2*act] == last ? 2*act : 2*act+1;
290 int x = (*plist)[2*act];
291 return x == last ? (*plist)[2*act+1] : x;
298 PathListIt& operator++() {
305 operator int() const {
310 const std::vector<int> *plist;
315 // Checks and applies 2-opt move (if it improves the tour)
316 bool checkOpt2(const PathListIt& i, const PathListIt& j) {
317 Node u = _gr.nodeFromId(i),
318 un = _gr.nodeFromId(i.next()),
319 v = _gr.nodeFromId(j),
320 vn = _gr.nodeFromId(j.next());
322 if (_cost[_gr.edge(u, un)] + _cost[_gr.edge(v, vn)] >
323 _cost[_gr.edge(u, v)] + _cost[_gr.edge(un, vn)])
325 _plist[PathListIt(_plist, i.next(), i).prevIndex()] = j.next();
326 _plist[PathListIt(_plist, j.next(), j).prevIndex()] = i.next();
328 _plist[i.nextIndex()] = j;
329 _plist[j.nextIndex()] = i;
337 // Executes the algorithm from the initial tour
341 for (PathListIt i(_plist); true; ++i) {
343 if (++j == 0 || ++j == 0) break;
344 for (; j != 0 && j != i.prev(); ++j) {
350 PathListIt i(_plist);
351 _path.push_back(_gr.nodeFromId(i));
352 for (++i; i != 0; ++i)
353 _path.push_back(_gr.nodeFromId(i));
355 _sum = _cost[_gr.edge(_path.back(), _path.front())];
356 for (int i = 0; i < int(_path.size())-1; ++i) {
357 _sum += _cost[_gr.edge(_path[i], _path[i+1])];
365 }; // namespace lemon