kpeter@1033
|
1 |
/* -*- mode: C++; indent-tabs-mode: nil; -*-
|
kpeter@1033
|
2 |
*
|
kpeter@1033
|
3 |
* This file is a part of LEMON, a generic C++ optimization library.
|
kpeter@1033
|
4 |
*
|
kpeter@1033
|
5 |
* Copyright (C) 2003-2010
|
kpeter@1033
|
6 |
* Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport
|
kpeter@1033
|
7 |
* (Egervary Research Group on Combinatorial Optimization, EGRES).
|
kpeter@1033
|
8 |
*
|
kpeter@1033
|
9 |
* Permission to use, modify and distribute this software is granted
|
kpeter@1033
|
10 |
* provided that this copyright notice appears in all copies. For
|
kpeter@1033
|
11 |
* precise terms see the accompanying LICENSE file.
|
kpeter@1033
|
12 |
*
|
kpeter@1033
|
13 |
* This software is provided "AS IS" with no warranty of any kind,
|
kpeter@1033
|
14 |
* express or implied, and with no claim as to its suitability for any
|
kpeter@1033
|
15 |
* purpose.
|
kpeter@1033
|
16 |
*
|
kpeter@1033
|
17 |
*/
|
kpeter@1033
|
18 |
|
f4c3@1031
|
19 |
#ifndef LEMON_OPT2_TSP_H
|
f4c3@1031
|
20 |
#define LEMON_OPT2_TSP_H
|
f4c3@1031
|
21 |
|
kpeter@1033
|
22 |
/// \ingroup tsp
|
kpeter@1033
|
23 |
/// \file
|
kpeter@1034
|
24 |
/// \brief 2-opt algorithm for symmetric TSP.
|
kpeter@1033
|
25 |
|
f4c3@1031
|
26 |
#include <vector>
|
f4c3@1031
|
27 |
#include <lemon/full_graph.h>
|
f4c3@1031
|
28 |
|
f4c3@1031
|
29 |
namespace lemon {
|
kpeter@1033
|
30 |
|
kpeter@1034
|
31 |
/// \ingroup tsp
|
kpeter@1034
|
32 |
///
|
kpeter@1033
|
33 |
/// \brief 2-opt algorithm for symmetric TSP.
|
kpeter@1033
|
34 |
///
|
kpeter@1033
|
35 |
/// Opt2Tsp implements the 2-opt heuristic for solving
|
kpeter@1033
|
36 |
/// symmetric \ref tsp "TSP".
|
kpeter@1033
|
37 |
///
|
kpeter@1033
|
38 |
/// This algorithm starts with an initial tour and iteratively improves it.
|
kpeter@1033
|
39 |
/// At each step, it removes two edges and the reconnects the created two
|
kpeter@1033
|
40 |
/// paths in the other way if the resulting tour is shorter.
|
kpeter@1033
|
41 |
/// The algorithm finishes when no such 2-opt move can be applied, and so
|
kpeter@1033
|
42 |
/// the tour is 2-optimal.
|
kpeter@1033
|
43 |
///
|
kpeter@1033
|
44 |
/// If no starting tour is given to the \ref run() function, then the
|
kpeter@1033
|
45 |
/// algorithm uses the node sequence determined by the node IDs.
|
kpeter@1033
|
46 |
/// Oherwise, it starts with the given tour.
|
kpeter@1033
|
47 |
///
|
kpeter@1036
|
48 |
/// This is a rather slow but effective method.
|
kpeter@1036
|
49 |
/// Its typical usage is the improvement of the result of a fast tour
|
kpeter@1036
|
50 |
/// construction heuristic (e.g. the InsertionTsp algorithm).
|
kpeter@1033
|
51 |
///
|
kpeter@1033
|
52 |
/// \tparam CM Type of the cost map.
|
f4c3@1031
|
53 |
template <typename CM>
|
kpeter@1033
|
54 |
class Opt2Tsp
|
kpeter@1033
|
55 |
{
|
kpeter@1033
|
56 |
public:
|
kpeter@1033
|
57 |
|
kpeter@1033
|
58 |
/// Type of the cost map
|
kpeter@1033
|
59 |
typedef CM CostMap;
|
kpeter@1033
|
60 |
/// Type of the edge costs
|
kpeter@1033
|
61 |
typedef typename CM::Value Cost;
|
kpeter@1033
|
62 |
|
f4c3@1031
|
63 |
private:
|
kpeter@1033
|
64 |
|
f4c3@1031
|
65 |
GRAPH_TYPEDEFS(FullGraph);
|
f4c3@1031
|
66 |
|
kpeter@1033
|
67 |
const FullGraph &_gr;
|
kpeter@1033
|
68 |
const CostMap &_cost;
|
kpeter@1033
|
69 |
Cost _sum;
|
kpeter@1033
|
70 |
std::vector<int> _plist;
|
kpeter@1033
|
71 |
std::vector<Node> _path;
|
kpeter@1033
|
72 |
|
f4c3@1031
|
73 |
public:
|
kpeter@1033
|
74 |
|
kpeter@1033
|
75 |
/// \brief Constructor
|
kpeter@1033
|
76 |
///
|
kpeter@1033
|
77 |
/// Constructor.
|
kpeter@1033
|
78 |
/// \param gr The \ref FullGraph "full graph" the algorithm runs on.
|
kpeter@1033
|
79 |
/// \param cost The cost map.
|
kpeter@1033
|
80 |
Opt2Tsp(const FullGraph &gr, const CostMap &cost)
|
kpeter@1033
|
81 |
: _gr(gr), _cost(cost) {}
|
kpeter@1033
|
82 |
|
kpeter@1033
|
83 |
/// \name Execution Control
|
kpeter@1033
|
84 |
/// @{
|
kpeter@1033
|
85 |
|
kpeter@1033
|
86 |
/// \brief Runs the algorithm from scratch.
|
kpeter@1033
|
87 |
///
|
kpeter@1033
|
88 |
/// This function runs the algorithm starting from the tour that is
|
kpeter@1033
|
89 |
/// determined by the node ID sequence.
|
kpeter@1033
|
90 |
///
|
kpeter@1033
|
91 |
/// \return The total cost of the found tour.
|
kpeter@1033
|
92 |
Cost run() {
|
kpeter@1033
|
93 |
_path.clear();
|
kpeter@1033
|
94 |
|
kpeter@1033
|
95 |
if (_gr.nodeNum() == 0) return _sum = 0;
|
kpeter@1033
|
96 |
else if (_gr.nodeNum() == 1) {
|
kpeter@1033
|
97 |
_path.push_back(_gr(0));
|
kpeter@1033
|
98 |
return _sum = 0;
|
f4c3@1031
|
99 |
}
|
kpeter@1033
|
100 |
else if (_gr.nodeNum() == 2) {
|
kpeter@1033
|
101 |
_path.push_back(_gr(0));
|
kpeter@1033
|
102 |
_path.push_back(_gr(1));
|
kpeter@1033
|
103 |
return _sum = 2 * _cost[_gr.edge(_gr(0), _gr(1))];
|
kpeter@1033
|
104 |
}
|
f4c3@1031
|
105 |
|
kpeter@1033
|
106 |
_plist.resize(2*_gr.nodeNum());
|
kpeter@1033
|
107 |
for (int i = 1; i < _gr.nodeNum()-1; ++i) {
|
kpeter@1033
|
108 |
_plist[2*i] = i-1;
|
kpeter@1033
|
109 |
_plist[2*i+1] = i+1;
|
f4c3@1031
|
110 |
}
|
kpeter@1033
|
111 |
_plist[0] = _gr.nodeNum()-1;
|
kpeter@1033
|
112 |
_plist[1] = 1;
|
kpeter@1033
|
113 |
_plist[2*_gr.nodeNum()-2] = _gr.nodeNum()-2;
|
kpeter@1033
|
114 |
_plist[2*_gr.nodeNum()-1] = 0;
|
kpeter@1033
|
115 |
|
kpeter@1033
|
116 |
return start();
|
f4c3@1031
|
117 |
}
|
f4c3@1031
|
118 |
|
kpeter@1034
|
119 |
/// \brief Runs the algorithm starting from the given tour.
|
kpeter@1033
|
120 |
///
|
kpeter@1033
|
121 |
/// This function runs the algorithm starting from the given tour.
|
kpeter@1033
|
122 |
///
|
kpeter@1033
|
123 |
/// \param tour The tour as a path structure. It must be a
|
kpeter@1033
|
124 |
/// \ref checkPath() "valid path" containing excactly n arcs.
|
kpeter@1033
|
125 |
///
|
kpeter@1033
|
126 |
/// \return The total cost of the found tour.
|
kpeter@1033
|
127 |
template <typename Path>
|
kpeter@1033
|
128 |
Cost run(const Path& tour) {
|
kpeter@1033
|
129 |
_path.clear();
|
kpeter@1033
|
130 |
|
kpeter@1033
|
131 |
if (_gr.nodeNum() == 0) return _sum = 0;
|
kpeter@1033
|
132 |
else if (_gr.nodeNum() == 1) {
|
kpeter@1033
|
133 |
_path.push_back(_gr(0));
|
kpeter@1033
|
134 |
return _sum = 0;
|
kpeter@1033
|
135 |
}
|
kpeter@1033
|
136 |
else if (_gr.nodeNum() == 2) {
|
kpeter@1033
|
137 |
_path.push_back(_gr(0));
|
kpeter@1033
|
138 |
_path.push_back(_gr(1));
|
kpeter@1033
|
139 |
return _sum = 2 * _cost[_gr.edge(_gr(0), _gr(1))];
|
kpeter@1033
|
140 |
}
|
kpeter@1033
|
141 |
|
kpeter@1033
|
142 |
_plist.resize(2*_gr.nodeNum());
|
kpeter@1033
|
143 |
typename Path::ArcIt it(tour);
|
kpeter@1033
|
144 |
int first = _gr.id(_gr.source(it)),
|
kpeter@1033
|
145 |
prev = first,
|
kpeter@1033
|
146 |
curr = _gr.id(_gr.target(it)),
|
kpeter@1033
|
147 |
next = -1;
|
kpeter@1033
|
148 |
_plist[2*first+1] = curr;
|
kpeter@1033
|
149 |
for (++it; it != INVALID; ++it) {
|
kpeter@1033
|
150 |
next = _gr.id(_gr.target(it));
|
kpeter@1033
|
151 |
_plist[2*curr] = prev;
|
kpeter@1033
|
152 |
_plist[2*curr+1] = next;
|
kpeter@1033
|
153 |
prev = curr;
|
kpeter@1033
|
154 |
curr = next;
|
kpeter@1033
|
155 |
}
|
kpeter@1033
|
156 |
_plist[2*first] = prev;
|
kpeter@1033
|
157 |
|
kpeter@1033
|
158 |
return start();
|
kpeter@1033
|
159 |
}
|
kpeter@1033
|
160 |
|
kpeter@1034
|
161 |
/// \brief Runs the algorithm starting from the given tour.
|
kpeter@1033
|
162 |
///
|
kpeter@1034
|
163 |
/// This function runs the algorithm starting from the given tour
|
kpeter@1034
|
164 |
/// (node sequence).
|
kpeter@1033
|
165 |
///
|
kpeter@1034
|
166 |
/// \param tour A vector that stores all <tt>Node</tt>s of the graph
|
kpeter@1034
|
167 |
/// in the desired order.
|
kpeter@1033
|
168 |
///
|
kpeter@1033
|
169 |
/// \return The total cost of the found tour.
|
kpeter@1034
|
170 |
Cost run(const std::vector<Node>& tour) {
|
kpeter@1033
|
171 |
_path.clear();
|
kpeter@1033
|
172 |
|
kpeter@1033
|
173 |
if (_gr.nodeNum() == 0) return _sum = 0;
|
kpeter@1033
|
174 |
else if (_gr.nodeNum() == 1) {
|
kpeter@1033
|
175 |
_path.push_back(_gr(0));
|
kpeter@1033
|
176 |
return _sum = 0;
|
kpeter@1033
|
177 |
}
|
kpeter@1033
|
178 |
else if (_gr.nodeNum() == 2) {
|
kpeter@1033
|
179 |
_path.push_back(_gr(0));
|
kpeter@1033
|
180 |
_path.push_back(_gr(1));
|
kpeter@1033
|
181 |
return _sum = 2 * _cost[_gr.edge(_gr(0), _gr(1))];
|
kpeter@1033
|
182 |
}
|
kpeter@1033
|
183 |
|
kpeter@1033
|
184 |
_plist.resize(2*_gr.nodeNum());
|
kpeter@1034
|
185 |
typename std::vector<Node>::const_iterator it = tour.begin();
|
kpeter@1033
|
186 |
int first = _gr.id(*it),
|
kpeter@1033
|
187 |
prev = first,
|
kpeter@1033
|
188 |
curr = _gr.id(*(++it)),
|
kpeter@1033
|
189 |
next = -1;
|
kpeter@1033
|
190 |
_plist[2*first+1] = curr;
|
kpeter@1033
|
191 |
for (++it; it != tour.end(); ++it) {
|
kpeter@1033
|
192 |
next = _gr.id(*it);
|
kpeter@1033
|
193 |
_plist[2*curr] = prev;
|
kpeter@1033
|
194 |
_plist[2*curr+1] = next;
|
kpeter@1033
|
195 |
prev = curr;
|
kpeter@1033
|
196 |
curr = next;
|
kpeter@1033
|
197 |
}
|
kpeter@1033
|
198 |
_plist[2*first] = curr;
|
kpeter@1033
|
199 |
_plist[2*curr] = prev;
|
kpeter@1033
|
200 |
_plist[2*curr+1] = first;
|
kpeter@1033
|
201 |
|
kpeter@1033
|
202 |
return start();
|
kpeter@1033
|
203 |
}
|
kpeter@1033
|
204 |
|
kpeter@1033
|
205 |
/// @}
|
kpeter@1033
|
206 |
|
kpeter@1033
|
207 |
/// \name Query Functions
|
kpeter@1033
|
208 |
/// @{
|
kpeter@1033
|
209 |
|
kpeter@1033
|
210 |
/// \brief The total cost of the found tour.
|
kpeter@1033
|
211 |
///
|
kpeter@1033
|
212 |
/// This function returns the total cost of the found tour.
|
kpeter@1033
|
213 |
///
|
kpeter@1033
|
214 |
/// \pre run() must be called before using this function.
|
kpeter@1033
|
215 |
Cost tourCost() const {
|
kpeter@1033
|
216 |
return _sum;
|
kpeter@1033
|
217 |
}
|
kpeter@1033
|
218 |
|
kpeter@1033
|
219 |
/// \brief Returns a const reference to the node sequence of the
|
kpeter@1033
|
220 |
/// found tour.
|
kpeter@1033
|
221 |
///
|
kpeter@1034
|
222 |
/// This function returns a const reference to a vector
|
kpeter@1033
|
223 |
/// that stores the node sequence of the found tour.
|
kpeter@1033
|
224 |
///
|
kpeter@1033
|
225 |
/// \pre run() must be called before using this function.
|
kpeter@1033
|
226 |
const std::vector<Node>& tourNodes() const {
|
kpeter@1033
|
227 |
return _path;
|
kpeter@1033
|
228 |
}
|
kpeter@1033
|
229 |
|
kpeter@1033
|
230 |
/// \brief Gives back the node sequence of the found tour.
|
kpeter@1033
|
231 |
///
|
kpeter@1033
|
232 |
/// This function copies the node sequence of the found tour into
|
kpeter@1033
|
233 |
/// the given standard container.
|
kpeter@1033
|
234 |
///
|
kpeter@1033
|
235 |
/// \pre run() must be called before using this function.
|
kpeter@1033
|
236 |
template <typename Container>
|
kpeter@1033
|
237 |
void tourNodes(Container &container) const {
|
kpeter@1033
|
238 |
container.assign(_path.begin(), _path.end());
|
kpeter@1033
|
239 |
}
|
kpeter@1033
|
240 |
|
kpeter@1033
|
241 |
/// \brief Gives back the found tour as a path.
|
kpeter@1033
|
242 |
///
|
kpeter@1033
|
243 |
/// This function copies the found tour as a list of arcs/edges into
|
kpeter@1033
|
244 |
/// the given \ref concept::Path "path structure".
|
kpeter@1033
|
245 |
///
|
kpeter@1033
|
246 |
/// \pre run() must be called before using this function.
|
kpeter@1033
|
247 |
template <typename Path>
|
kpeter@1033
|
248 |
void tour(Path &path) const {
|
kpeter@1033
|
249 |
path.clear();
|
kpeter@1033
|
250 |
for (int i = 0; i < int(_path.size()) - 1; ++i) {
|
kpeter@1033
|
251 |
path.addBack(_gr.arc(_path[i], _path[i+1]));
|
kpeter@1033
|
252 |
}
|
kpeter@1033
|
253 |
if (int(_path.size()) >= 2) {
|
kpeter@1033
|
254 |
path.addBack(_gr.arc(_path.back(), _path.front()));
|
kpeter@1033
|
255 |
}
|
kpeter@1033
|
256 |
}
|
kpeter@1033
|
257 |
|
kpeter@1033
|
258 |
/// @}
|
kpeter@1033
|
259 |
|
f4c3@1031
|
260 |
private:
|
kpeter@1033
|
261 |
|
kpeter@1033
|
262 |
// Iterator class for the linked list storage of the tour
|
kpeter@1033
|
263 |
class PathListIt {
|
f4c3@1031
|
264 |
public:
|
kpeter@1033
|
265 |
PathListIt(const std::vector<int> &pl, int i=0)
|
kpeter@1033
|
266 |
: plist(&pl), act(i), last(pl[2*act]) {}
|
kpeter@1033
|
267 |
PathListIt(const std::vector<int> &pl, int i, int l)
|
kpeter@1033
|
268 |
: plist(&pl), act(i), last(l) {}
|
f4c3@1031
|
269 |
|
kpeter@1033
|
270 |
int nextIndex() const {
|
kpeter@1033
|
271 |
return (*plist)[2*act] == last ? 2*act+1 : 2*act;
|
f4c3@1031
|
272 |
}
|
kpeter@1033
|
273 |
|
kpeter@1033
|
274 |
int prevIndex() const {
|
kpeter@1033
|
275 |
return (*plist)[2*act] == last ? 2*act : 2*act+1;
|
f4c3@1031
|
276 |
}
|
kpeter@1033
|
277 |
|
f4c3@1031
|
278 |
int next() const {
|
kpeter@1033
|
279 |
int x = (*plist)[2*act];
|
kpeter@1033
|
280 |
return x == last ? (*plist)[2*act+1] : x;
|
f4c3@1031
|
281 |
}
|
f4c3@1031
|
282 |
|
f4c3@1031
|
283 |
int prev() const {
|
kpeter@1033
|
284 |
return last;
|
f4c3@1031
|
285 |
}
|
kpeter@1033
|
286 |
|
kpeter@1033
|
287 |
PathListIt& operator++() {
|
f4c3@1031
|
288 |
int tmp = act;
|
f4c3@1031
|
289 |
act = next();
|
f4c3@1031
|
290 |
last = tmp;
|
f4c3@1031
|
291 |
return *this;
|
f4c3@1031
|
292 |
}
|
kpeter@1033
|
293 |
|
f4c3@1031
|
294 |
operator int() const {
|
f4c3@1031
|
295 |
return act;
|
f4c3@1031
|
296 |
}
|
kpeter@1033
|
297 |
|
f4c3@1031
|
298 |
private:
|
kpeter@1033
|
299 |
const std::vector<int> *plist;
|
f4c3@1031
|
300 |
int act;
|
f4c3@1031
|
301 |
int last;
|
f4c3@1031
|
302 |
};
|
f4c3@1031
|
303 |
|
kpeter@1033
|
304 |
// Checks and applies 2-opt move (if it improves the tour)
|
kpeter@1033
|
305 |
bool checkOpt2(const PathListIt& i, const PathListIt& j) {
|
kpeter@1033
|
306 |
Node u = _gr.nodeFromId(i),
|
kpeter@1033
|
307 |
un = _gr.nodeFromId(i.next()),
|
kpeter@1033
|
308 |
v = _gr.nodeFromId(j),
|
kpeter@1033
|
309 |
vn = _gr.nodeFromId(j.next());
|
f4c3@1031
|
310 |
|
kpeter@1033
|
311 |
if (_cost[_gr.edge(u, un)] + _cost[_gr.edge(v, vn)] >
|
kpeter@1033
|
312 |
_cost[_gr.edge(u, v)] + _cost[_gr.edge(un, vn)])
|
kpeter@1033
|
313 |
{
|
kpeter@1033
|
314 |
_plist[PathListIt(_plist, i.next(), i).prevIndex()] = j.next();
|
kpeter@1033
|
315 |
_plist[PathListIt(_plist, j.next(), j).prevIndex()] = i.next();
|
f4c3@1031
|
316 |
|
kpeter@1033
|
317 |
_plist[i.nextIndex()] = j;
|
kpeter@1033
|
318 |
_plist[j.nextIndex()] = i;
|
f4c3@1031
|
319 |
|
kpeter@1033
|
320 |
return true;
|
f4c3@1031
|
321 |
}
|
kpeter@1033
|
322 |
|
f4c3@1031
|
323 |
return false;
|
kpeter@1033
|
324 |
}
|
f4c3@1031
|
325 |
|
kpeter@1033
|
326 |
// Executes the algorithm from the initial tour
|
kpeter@1033
|
327 |
Cost start() {
|
f4c3@1031
|
328 |
|
kpeter@1033
|
329 |
restart_search:
|
kpeter@1033
|
330 |
for (PathListIt i(_plist); true; ++i) {
|
kpeter@1033
|
331 |
PathListIt j = i;
|
kpeter@1033
|
332 |
if (++j == 0 || ++j == 0) break;
|
kpeter@1033
|
333 |
for (; j != 0 && j != i.prev(); ++j) {
|
kpeter@1033
|
334 |
if (checkOpt2(i, j))
|
kpeter@1033
|
335 |
goto restart_search;
|
f4c3@1031
|
336 |
}
|
f4c3@1031
|
337 |
}
|
f4c3@1031
|
338 |
|
kpeter@1033
|
339 |
PathListIt i(_plist);
|
kpeter@1033
|
340 |
_path.push_back(_gr.nodeFromId(i));
|
kpeter@1033
|
341 |
for (++i; i != 0; ++i)
|
kpeter@1033
|
342 |
_path.push_back(_gr.nodeFromId(i));
|
f4c3@1031
|
343 |
|
kpeter@1033
|
344 |
_sum = _cost[_gr.edge(_path.back(), _path.front())];
|
kpeter@1033
|
345 |
for (int i = 0; i < int(_path.size())-1; ++i) {
|
kpeter@1033
|
346 |
_sum += _cost[_gr.edge(_path[i], _path[i+1])];
|
kpeter@1033
|
347 |
}
|
f4c3@1031
|
348 |
|
f4c3@1031
|
349 |
return _sum;
|
f4c3@1031
|
350 |
}
|
f4c3@1031
|
351 |
|
f4c3@1031
|
352 |
};
|
f4c3@1031
|
353 |
|
f4c3@1031
|
354 |
}; // namespace lemon
|
f4c3@1031
|
355 |
|
f4c3@1031
|
356 |
#endif
|