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