equal
deleted
inserted
replaced
1 /* -*- mode: C++; indent-tabs-mode: nil; -*- |
1 /* -*- mode: C++; indent-tabs-mode: nil; -*- |
2 * |
2 * |
3 * This file is a part of LEMON, a generic C++ optimization library. |
3 * This file is a part of LEMON, a generic C++ optimization library. |
4 * |
4 * |
5 * Copyright (C) 2003-2010 |
5 * Copyright (C) 2003-2013 |
6 * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport |
6 * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport |
7 * (Egervary Research Group on Combinatorial Optimization, EGRES). |
7 * (Egervary Research Group on Combinatorial Optimization, EGRES). |
8 * |
8 * |
9 * Permission to use, modify and distribute this software is granted |
9 * Permission to use, modify and distribute this software is granted |
10 * provided that this copyright notice appears in all copies. For |
10 * provided that this copyright notice appears in all copies. For |
28 #include <lemon/kruskal.h> |
28 #include <lemon/kruskal.h> |
29 #include <lemon/matching.h> |
29 #include <lemon/matching.h> |
30 #include <lemon/euler.h> |
30 #include <lemon/euler.h> |
31 |
31 |
32 namespace lemon { |
32 namespace lemon { |
33 |
33 |
34 /// \ingroup tsp |
34 /// \ingroup tsp |
35 /// |
35 /// |
36 /// \brief Christofides algorithm for symmetric TSP. |
36 /// \brief Christofides algorithm for symmetric TSP. |
37 /// |
37 /// |
38 /// ChristofidesTsp implements Christofides' heuristic for solving |
38 /// ChristofidesTsp implements Christofides' heuristic for solving |
106 else if (_gr.nodeNum() == 2) { |
106 else if (_gr.nodeNum() == 2) { |
107 _path.push_back(_gr(0)); |
107 _path.push_back(_gr(0)); |
108 _path.push_back(_gr(1)); |
108 _path.push_back(_gr(1)); |
109 return _sum = 2 * _cost[_gr.edge(_gr(0), _gr(1))]; |
109 return _sum = 2 * _cost[_gr.edge(_gr(0), _gr(1))]; |
110 } |
110 } |
111 |
111 |
112 // Compute min. cost spanning tree |
112 // Compute min. cost spanning tree |
113 std::vector<Edge> tree; |
113 std::vector<Edge> tree; |
114 kruskal(_gr, _cost, std::back_inserter(tree)); |
114 kruskal(_gr, _cost, std::back_inserter(tree)); |
115 |
115 |
116 FullGraph::NodeMap<int> deg(_gr, 0); |
116 FullGraph::NodeMap<int> deg(_gr, 0); |
117 for (int i = 0; i != int(tree.size()); ++i) { |
117 for (int i = 0; i != int(tree.size()); ++i) { |
118 Edge e = tree[i]; |
118 Edge e = tree[i]; |
119 ++deg[_gr.u(e)]; |
119 ++deg[_gr.u(e)]; |
120 ++deg[_gr.v(e)]; |
120 ++deg[_gr.v(e)]; |
123 // Copy the induced subgraph of odd nodes |
123 // Copy the induced subgraph of odd nodes |
124 std::vector<Node> odd_nodes; |
124 std::vector<Node> odd_nodes; |
125 for (NodeIt u(_gr); u != INVALID; ++u) { |
125 for (NodeIt u(_gr); u != INVALID; ++u) { |
126 if (deg[u] % 2 == 1) odd_nodes.push_back(u); |
126 if (deg[u] % 2 == 1) odd_nodes.push_back(u); |
127 } |
127 } |
128 |
128 |
129 SmartGraph sgr; |
129 SmartGraph sgr; |
130 SmartGraph::EdgeMap<Cost> scost(sgr); |
130 SmartGraph::EdgeMap<Cost> scost(sgr); |
131 for (int i = 0; i != int(odd_nodes.size()); ++i) { |
131 for (int i = 0; i != int(odd_nodes.size()); ++i) { |
132 sgr.addNode(); |
132 sgr.addNode(); |
133 } |
133 } |
137 SmartGraph::Edge e = |
137 SmartGraph::Edge e = |
138 sgr.addEdge(sgr.nodeFromId(i), sgr.nodeFromId(j)); |
138 sgr.addEdge(sgr.nodeFromId(i), sgr.nodeFromId(j)); |
139 scost[e] = -_cost[_gr.edge(odd_nodes[i], odd_nodes[j])]; |
139 scost[e] = -_cost[_gr.edge(odd_nodes[i], odd_nodes[j])]; |
140 } |
140 } |
141 } |
141 } |
142 |
142 |
143 // Compute min. cost perfect matching |
143 // Compute min. cost perfect matching |
144 MaxWeightedPerfectMatching<SmartGraph, SmartGraph::EdgeMap<Cost> > |
144 MaxWeightedPerfectMatching<SmartGraph, SmartGraph::EdgeMap<Cost> > |
145 mwpm(sgr, scost); |
145 mwpm(sgr, scost); |
146 mwpm.run(); |
146 mwpm.run(); |
147 |
147 |
148 for (SmartGraph::EdgeIt e(sgr); e != INVALID; ++e) { |
148 for (SmartGraph::EdgeIt e(sgr); e != INVALID; ++e) { |
149 if (mwpm.matching(e)) { |
149 if (mwpm.matching(e)) { |
150 tree.push_back( _gr.edge(odd_nodes[sgr.id(sgr.u(e))], |
150 tree.push_back( _gr.edge(odd_nodes[sgr.id(sgr.u(e))], |
151 odd_nodes[sgr.id(sgr.v(e))]) ); |
151 odd_nodes[sgr.id(sgr.v(e))]) ); |
152 } |
152 } |
153 } |
153 } |
154 |
154 |
155 // Join the spanning tree and the matching |
155 // Join the spanning tree and the matching |
156 sgr.clear(); |
156 sgr.clear(); |
157 for (int i = 0; i != _gr.nodeNum(); ++i) { |
157 for (int i = 0; i != _gr.nodeNum(); ++i) { |
158 sgr.addNode(); |
158 sgr.addNode(); |
159 } |
159 } |
160 for (int i = 0; i != int(tree.size()); ++i) { |
160 for (int i = 0; i != int(tree.size()); ++i) { |
180 |
180 |
181 return _sum; |
181 return _sum; |
182 } |
182 } |
183 |
183 |
184 /// @} |
184 /// @} |
185 |
185 |
186 /// \name Query Functions |
186 /// \name Query Functions |
187 /// @{ |
187 /// @{ |
188 |
188 |
189 /// \brief The total cost of the found tour. |
189 /// \brief The total cost of the found tour. |
190 /// |
190 /// |
191 /// This function returns the total cost of the found tour. |
191 /// This function returns the total cost of the found tour. |
192 /// |
192 /// |
193 /// \pre run() must be called before using this function. |
193 /// \pre run() must be called before using this function. |
194 Cost tourCost() const { |
194 Cost tourCost() const { |
195 return _sum; |
195 return _sum; |
196 } |
196 } |
197 |
197 |
198 /// \brief Returns a const reference to the node sequence of the |
198 /// \brief Returns a const reference to the node sequence of the |
199 /// found tour. |
199 /// found tour. |
200 /// |
200 /// |
201 /// This function returns a const reference to a vector |
201 /// This function returns a const reference to a vector |
202 /// that stores the node sequence of the found tour. |
202 /// that stores the node sequence of the found tour. |
225 /// \pre run() must be called before using this function. |
225 /// \pre run() must be called before using this function. |
226 template <typename Iterator> |
226 template <typename Iterator> |
227 void tourNodes(Iterator out) const { |
227 void tourNodes(Iterator out) const { |
228 std::copy(_path.begin(), _path.end(), out); |
228 std::copy(_path.begin(), _path.end(), out); |
229 } |
229 } |
230 |
230 |
231 /// \brief Gives back the found tour as a path. |
231 /// \brief Gives back the found tour as a path. |
232 /// |
232 /// |
233 /// This function copies the found tour as a list of arcs/edges into |
233 /// This function copies the found tour as a list of arcs/edges into |
234 /// the given \ref lemon::concepts::Path "path structure". |
234 /// the given \ref lemon::concepts::Path "path structure". |
235 /// |
235 /// |
242 } |
242 } |
243 if (int(_path.size()) >= 2) { |
243 if (int(_path.size()) >= 2) { |
244 path.addBack(_gr.arc(_path.back(), _path.front())); |
244 path.addBack(_gr.arc(_path.back(), _path.front())); |
245 } |
245 } |
246 } |
246 } |
247 |
247 |
248 /// @} |
248 /// @} |
249 |
249 |
250 }; |
250 }; |
251 |
251 |
252 }; // namespace lemon |
252 }; // namespace lemon |
253 |
253 |
254 #endif |
254 #endif |