29#include <py2cpp/range.hpp>
30#include <py2cpp/set.hpp>
49template <
typename Node,
typename WeightFunc>
74 -> std::vector<std::pair<Node, Node>> {
75 constexpr double INF = std::numeric_limits<double>::max();
77 std::vector<bool>
in_mst(
n,
false);
78 std::vector<double>
key(
n,
INF);
79 std::vector<Node> parent(
n, Node{0});
88 if (!
in_mst[
static_cast<size_t>(
v)] &&
key[
static_cast<size_t>(
v)] <
best) {
95 in_mst[
static_cast<size_t>(
u)] =
true;
99 if (!
in_mst[
static_cast<size_t>(
v)]) {
100 const double w = std::forward<WeightFunc>(weight)(
u,
v);
101 auto&
kv =
key[
static_cast<size_t>(
v)];
104 parent[
static_cast<size_t>(
v)] =
u;
110 std::vector<std::pair<Node, Node>> edges;
111 edges.reserve(
n - 1);
113 const auto p = parent[
static_cast<size_t>(
v)];
115 edges.emplace_back(
p,
v);
123 template <
typename Node>
125 -> std::vector<Node> {
126 std::vector<int>
deg(
n, 0);
128 ++
deg[
static_cast<size_t>(
u)];
129 ++
deg[
static_cast<size_t>(
v)];
131 std::vector<Node>
odd;
133 if (
deg[
static_cast<size_t>(
v)] % 2 != 0)
odd.push_back(
v);
145 template <
typename Node,
typename WeightFunc>
147 -> std::vector<std::pair<Node, Node>> {
149 if (
k < 2)
return {};
152 std::vector<std::tuple<double, Node, Node>> edges;
153 edges.reserve(
k * (
k - 1) / 2);
154 for (
size_t i = 0;
i <
k; ++
i) {
155 for (
size_t j =
i + 1;
j <
k; ++
j) {
160 std::sort(edges.begin(), edges.end(),
161 [](
const auto&
a,
const auto&
b) { return std::get<0>(a) < std::get<0>(b); });
163 std::vector<bool>
used(
k,
false);
164 std::vector<std::pair<Node, Node>>
matching;
167 for (
const auto& [
w,
u,
v] : edges) {
171 for (
size_t t = 0;
t <
k; ++
t) {
190 template <
typename Node>
193 -> std::vector<std::multiset<Node>> {
194 std::vector<std::multiset<Node>> adj(
n);
195 const auto add = [&](Node
a, Node
b) {
196 adj[
static_cast<size_t>(
a)].
insert(
b);
197 adj[
static_cast<size_t>(
b)].
insert(
a);
213 template <
typename Node>
auto hierholzer(std::vector<std::multiset<Node>> adj, Node
start)
214 -> std::vector<std::pair<Node, Node>>;
220 template <
typename Node>
222 -> std::vector<Node> {
223 std::vector<Node>
path;
250template <
typename Graph,
typename WeightFunc>
252 using Node =
typename Graph::node_t;
253 const size_t n =
G.number_of_nodes();
255 if (
n == 0)
return {};
256 if (
n == 1)
return {Node{0}, Node{0}};
259 const auto mst_edges = detail::prim_mst<Node>(
n, weight);
272 const auto eulerian_circuit = detail::hierholzer<Node>(std::move(adj), Node{0});
296template <
typename Graph,
typename WeightFunc>
298 -> std::vector<typename Graph::node_t> {
306 if (
j -
i == 1)
continue;
310 + std::forward<WeightFunc>(weight)(
path[
i],
path[
j + 1]);
312 if (
delta < -1.0e-12) {
340template <
typename Graph,
typename WeightFunc>
342 -> std::vector<typename Graph::node_t> {
Read-only map of maps of maps (view into a dict-of-dict-of-dict structure)
Definition coreviews.hpp:109
AdjacencyView(Atlas &d)
Construct an AdjacencyView from an Atlas container.
Definition coreviews.hpp:115
auto begin() const
Get iterator to the beginning of the view.
Definition coreviews.hpp:55
auto size() const -> size_t
Get the number of elements in the view.
Definition coreviews.hpp:49
Undirected graph data structure for XNetwork.
Definition hadlock.hpp:40
auto find_odd_degree_nodes(const std::vector< std::pair< Node, Node > > &mst_edges, size_t n) -> std::vector< Node >
Collect vertices with odd degree in the MST.
Definition tsp.hpp:124
auto shortcut_eulerian(const std::vector< std::pair< Node, Node > > &eulerian_circuit) -> std::vector< Node >
Convert an Eulerian circuit to a Hamiltonian cycle by skipping repeated vertices (shortcut).
Definition tsp.hpp:221
auto prim_mst(size_t n, WeightFunc &&weight) -> std::vector< std::pair< Node, Node > >
Prim's MST for dense (complete) graphs - O(n^2).
Definition tsp.hpp:73
auto greedy_min_weight_matching(const std::vector< Node > &odd_nodes, WeightFunc &&weight) -> std::vector< std::pair< Node, Node > >
Greedy minimum-weight perfect matching - O(k^2 log k).
Definition tsp.hpp:146
auto hierholzer(std::vector< std::multiset< Node > > adj, Node start) -> std::vector< std::pair< Node, Node > >
Hierholzer's algorithm - find an Eulerian circuit.
auto build_multigraph(size_t n, const std::vector< std::pair< Node, Node > > &mst_edges, const std::vector< std::pair< Node, Node > > &matching_edges) -> std::vector< std::multiset< Node > >
Build a multigraph adjacency list (MST + matching).
Definition tsp.hpp:191
constexpr int INF
Definition hadlock.hpp:42
auto christofides_tsp(const Graph &G, WeightFunc &&weight) -> std::vector< typename Graph::node_t >
Solve Metric TSP using the Christofides approximation algorithm.
Definition tsp.hpp:251
double calculate_total_distance(const std::vector< Node > &path, WeightFunc &&weight)
Compute the total length of a Hamiltonian path/cycle.
Definition tsp.hpp:50
auto two_opt(std::vector< typename Graph::node_t > path, const Graph &G, WeightFunc &&weight) -> std::vector< typename Graph::node_t >
Refine a TSP tour using 2-opt neighbourhood search.
Definition tsp.hpp:297
auto solve_christofides_2opt_tsp(const Graph &G, WeightFunc &&weight) -> std::vector< typename Graph::node_t >
Solve Metric TSP using Christofides followed by 2-Opt refinement.
Definition tsp.hpp:341