diff -r 62ba43576f85 -r 9a51db038228 lemon/greedy_tsp.h --- a/lemon/greedy_tsp.h Sat Jan 08 22:49:09 2011 +0100 +++ b/lemon/greedy_tsp.h Sat Jan 08 22:51:16 2011 +0100 @@ -1,174 +1,236 @@ +/* -*- mode: C++; indent-tabs-mode: nil; -*- + * + * This file is a part of LEMON, a generic C++ optimization library. + * + * Copyright (C) 2003-2010 + * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport + * (Egervary Research Group on Combinatorial Optimization, EGRES). + * + * Permission to use, modify and distribute this software is granted + * provided that this copyright notice appears in all copies. For + * precise terms see the accompanying LICENSE file. + * + * This software is provided "AS IS" with no warranty of any kind, + * express or implied, and with no claim as to its suitability for any + * purpose. + * + */ + #ifndef LEMON_GREEDY_TSP_H #define LEMON_GREEDY_TSP_H -#include +/// \ingroup tsp +/// \file +/// \brief Greedy algorithm for symmetric TSP + +#include +#include #include #include -#include namespace lemon { - namespace greedy_tsp_helper { + /// \brief Greedy algorithm for symmetric TSP. + /// + /// GreedyTsp implements the greedy heuristic for solving + /// symmetric \ref tsp "TSP". + /// + /// This algorithm is quite similar to the \ref NearestNeighborTsp + /// "nearest neighbor" heuristic, but it maintains a set of disjoint paths. + /// At each step, the shortest possible edge is added to these paths + /// as long as it does not create a cycle of less than n edges and it does + /// not increase the degree of any node above two. + /// + /// This method runs in O(n2log(n)) time. + /// It quickly finds an effectively short tour for most TSP + /// instances, but in special cases, it could yield a really bad + /// (or even the worst) solution. + /// + /// \tparam CM Type of the cost map. + template + class GreedyTsp + { + public: - template - class KeyComp { - typedef typename CostMap::Key Key; - const CostMap &cost; + /// Type of the cost map + typedef CM CostMap; + /// Type of the edge costs + typedef typename CM::Value Cost; + + private: + + GRAPH_TYPEDEFS(FullGraph); + + const FullGraph &_gr; + const CostMap &_cost; + Cost _sum; + std::vector _path; + private: + + // Functor class to compare edges by their costs + class EdgeComp { + private: + const CostMap &_cost; + public: - KeyComp(const CostMap &_cost) : cost(_cost) {} - - bool operator() (const Key &a, const Key &b) const { - return cost[a] < cost[b]; + EdgeComp(const CostMap &cost) : _cost(cost) {} + + bool operator()(const Edge &a, const Edge &b) const { + return _cost[a] < _cost[b]; } - }; + }; - - template - L vectorConvert(const std::vector &_path) { - return L(_path.begin(), _path.end()); - } - - template <> - std::vector vectorConvert(const std::vector &_path) { - return _path; - } - - } + public: + /// \brief Constructor + /// + /// Constructor. + /// \param gr The \ref FullGraph "full graph" the algorithm runs on. + /// \param cost The cost map. + GreedyTsp(const FullGraph &gr, const CostMap &cost) + : _gr(gr), _cost(cost) {} - template - class GreedyTsp { - private: - GRAPH_TYPEDEFS(FullGraph); - - public: - typedef CM CostMap; - typedef typename CM::Value Cost; - - GreedyTsp(const FullGraph &gr, const CostMap &cost) : _gr(gr), _cost(cost) {} + /// \name Execution Control + /// @{ + /// \brief Runs the algorithm. + /// + /// This function runs the algorithm. + /// + /// \return The total cost of the found tour. Cost run() { - typedef UnionFind > Union; - _nodes.clear(); - - std::vector path; - path.resize(_gr.nodeNum()*2, -1); - - std::vector sorted_edges; + _path.clear(); + + if (_gr.nodeNum() == 0) return _sum = 0; + else if (_gr.nodeNum() == 1) { + _path.push_back(_gr(0)); + return _sum = 0; + } + + std::vector plist; + plist.resize(_gr.nodeNum()*2, -1); + + std::vector sorted_edges; sorted_edges.reserve(_gr.edgeNum()); - for (EdgeIt n(_gr); n != INVALID; ++n) - sorted_edges.push_back(n); + for (EdgeIt e(_gr); e != INVALID; ++e) + sorted_edges.push_back(e); + std::sort(sorted_edges.begin(), sorted_edges.end(), EdgeComp(_cost)); - std::sort(sorted_edges.begin(), sorted_edges.end(), greedy_tsp_helper::KeyComp(_cost)); + FullGraph::NodeMap item_int_map(_gr); + UnionFind > union_find(item_int_map); + for (NodeIt n(_gr); n != INVALID; ++n) + union_find.insert(n); - FullGraph::NodeMap nodemap(_gr); - Union unionfind(nodemap); - - for (NodeIt n(_gr); n != INVALID; ++n) - unionfind.insert(n); - FullGraph::NodeMap degree(_gr, 0); int nodesNum = 0, i = 0; + while (nodesNum != _gr.nodeNum()-1) { + Edge e = sorted_edges[i++]; + Node u = _gr.u(e), + v = _gr.v(e); - while ( nodesNum != _gr.nodeNum()-1 ) { - const Edge &e = sorted_edges[i]; - - const Node u = _gr.u(e), - v = _gr.v(e); - - if (degree[u]<=1 && degree[v]<=1) { - if (unionfind.join(u, v)) { + if (degree[u] <= 1 && degree[v] <= 1) { + if (union_find.join(u, v)) { + const int uid = _gr.id(u), + vid = _gr.id(v); + + plist[uid*2 + degree[u]] = vid; + plist[vid*2 + degree[v]] = uid; + ++degree[u]; ++degree[v]; ++nodesNum; - - const int uid = _gr.id(u), - vid = _gr.id(v); - - - path[uid*2 + (path[uid*2]==-1 ? 0 : 1)] = vid; - path[vid*2 + (path[vid*2]==-1 ? 0 : 1)] = uid; } } - - ++i; } - for (int i=0, n=-1; i<_gr.nodeNum()*2; ++i) { - if (path[i] == -1) { + if (plist[i] == -1) { if (n==-1) { n = i; } else { - path[n] = i/2; - path[i] = n/2; + plist[n] = i/2; + plist[i] = n/2; break; } } } - - for (int i=0, j=0, last=-1; i!=_gr.nodeNum(); ++i) { - _nodes.push_back(_gr.nodeFromId(j)); - - if (path[2*j] != last) { - last = j; - j = path[2*j]; + for (int i=0, next=0, last=-1; i!=_gr.nodeNum(); ++i) { + _path.push_back(_gr.nodeFromId(next)); + if (plist[2*next] != last) { + last = next; + next = plist[2*next]; } else { - last = j; - j = path[2*j+1]; + last = next; + next = plist[2*next+1]; } } - _sum = _cost[_gr.edge(_nodes.back(), _nodes.front())]; - for (unsigned int i=0; i<_nodes.size()-1; ++i) - _sum += _cost[_gr.edge(_nodes[i], _nodes[i+1])]; + _sum = _cost[_gr.edge(_path.back(), _path.front())]; + for (int i = 0; i < int(_path.size())-1; ++i) { + _sum += _cost[_gr.edge(_path[i], _path[i+1])]; + } return _sum; } + /// @} + /// \name Query Functions + /// @{ - template - void tourNodes(L &container) { - container(greedy_tsp_helper::vectorConvert(_nodes)); - } - - template