Aleph-w 3.0
A C++ Library for Data Structures and Algorithms
Loading...
Searching...
No Matches
centroid_decomposition_example.cc
Go to the documentation of this file.
1/*
2 Aleph_w
3
4 Data structures & Algorithms
5 version 2.0.0b
6 https://github.com/lrleon/Aleph-w
7
8 This file is part of Aleph-w library
9
10 Copyright (c) 2002-2026 Leandro Rabindranath Leon
11
12 Permission is hereby granted, free of charge, to any person obtaining a copy
13 of this software and associated documentation files (the "Software"), to deal
14 in the Software without restriction, including without limitation the rights
15 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
16 copies of the Software, and to permit persons to whom the Software is
17 furnished to do so, subject to the following conditions:
18
19 The above copyright notice and this permission notice shall be included in all
20 copies or substantial portions of the Software.
21
22 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
23 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
24 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
25 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
26 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
27 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
28 SOFTWARE.
29*/
30
31
49# include <Tree_Decomposition.H>
50# include <tpl_graph.H>
51
52# include <algorithm>
53# include <array>
54# include <cassert>
55# include <format>
56# include <iostream>
57# include <limits>
58
59using namespace Aleph;
60
76int main()
77{
79 using Node = G::Node;
80
81 G g;
82
83 // 0
84 // / | | (edge)
85 // 1 2 3
86 // / \ |
87 // 4 5 6
88 // / | | (edge)
89 // 7 8 9
90 // |
91 // 10
92
93 auto * n0 = g.insert_node(0);
94 auto * n1 = g.insert_node(1);
95 auto * n2 = g.insert_node(2);
96 auto * n3 = g.insert_node(3);
97 auto * n4 = g.insert_node(4);
98 auto * n5 = g.insert_node(5);
99 auto * n6 = g.insert_node(6);
100 auto * n7 = g.insert_node(7);
101 auto * n8 = g.insert_node(8);
102 auto * n9 = g.insert_node(9);
103 auto * n10 = g.insert_node(10);
104
105 g.insert_arc(n0, n1, 1);
106 g.insert_arc(n0, n2, 1);
107 g.insert_arc(n0, n3, 1);
108 g.insert_arc(n1, n4, 1);
109 g.insert_arc(n1, n5, 1);
110 g.insert_arc(n3, n6, 1);
111 g.insert_arc(n6, n7, 1);
112 g.insert_arc(n6, n8, 1);
113 g.insert_arc(n6, n9, 1);
114 g.insert_arc(n9, n10, 1);
115
117 Heavy_Light_Decomposition<G> hld(g, n0); // oracle distance for assertions
118
119 const size_t n = cd.size();
120 const size_t INF = std::numeric_limits<size_t>::max() / 4;
121
122 // --- Build label_by_id and node_by_id keyed on centroid IDs ---
123 // This avoids assuming cd.id_of(ni) == i (which would be fragile and
124 // graph-backend-dependent). Both cd and hld share the same Rooted_Tree_Topology
125 // ID space (same Node_Iterator order on the same graph object), so
126 // hld.distance_id(u, v) is valid with centroid IDs.
127
128 const std::array nodes_arr = { n0, n1, n2, n3, n4, n5, n6, n7, n8, n9, n10 };
129 const std::array village_label = {
130 "Village-0", "Village-1", "Village-2", "Village-3", "Village-4",
131 "Village-5", "Village-6", "Village-7", "Village-8", "Village-9",
132 "Village-10"
133 };
134
137
138 for (size_t i = 0; i < n; ++i)
139 {
140 label_by_id(i) = "";
141 node_by_id(i) = nullptr;
142 }
143
144 for (size_t i = 0; i < nodes_arr.size(); ++i)
145 {
146 const size_t id = cd.id_of(nodes_arr[i]);
147 label_by_id(id) = village_label[i];
148 node_by_id(id) = nodes_arr[i];
149 }
150
151 // --- Per-node bookkeeping arrays indexed by centroid ID ---
152 auto best = Array<size_t>::create(n);
153 auto active = Array<char>::create(n);
154
155 for (size_t i = 0; i < n; ++i)
156 {
157 best(i) = INF;
158 active(i) = 0;
159 }
160
161 // Activate a village by centroid ID: propagate its distance to every
162 // centroid ancestor so query() can find it later in O(log n).
163 auto activate = [&](const size_t u)
164 {
165 active(u) = 1;
167 u,
168 [&](const size_t c, const size_t d, const size_t)
169 {
170 if (d < best(c))
171 best(c) = d;
172 });
173 };
174
175 // Query the nearest active village from village u (centroid ID).
176 auto query = [&](const size_t u)
177 {
178 size_t ans = INF;
180 u,
181 [&](const size_t c, const size_t d, const size_t)
182 {
183 if (best(c) != INF)
184 ans = std::min(ans, best(c) + d);
185 });
186 return ans;
187 };
188
189 // Brute-force oracle: scan all active nodes and use HLD for exact distance.
190 // Uses centroid IDs throughout (valid since cd and hld share the same topology).
191 auto brute_query = [&](const size_t u)
192 {
193 size_t ans = INF;
194 for (size_t v = 0; v < n; ++v)
195 if (active(v))
196 ans = std::min(ans, hld.distance_id(u, v));
197 return ans;
198 };
199
200 // --- Demo ---
201
202 std::cout << std::format("=== Emergency Response Network (Centroid Decomposition) ===\n\n");
203 std::cout << std::format("Centroid root: {} (id={})\n\n",
205 cd.centroid_root_id());
206
207 std::cout << std::format("Centroid chain for Village-10:\n");
209 cd.id_of(n10),
210 [&](const size_t c, const size_t d, const size_t k)
211 {
212 std::cout << std::format(" k={} centroid={} dist={}\n", k, label_by_id(c), d);
213 });
214
215 std::cout << std::format("\nActivate team at Village-0 and Village-8\n");
216 activate(cd.id_of(n0));
217 activate(cd.id_of(n8));
218
219 for (Node * node : { n4, n5, n7, n10 })
220 {
221 const size_t u = cd.id_of(node);
222 const size_t ans = query(u);
223 const size_t brute = brute_query(u);
224 std::cout << std::format(" nearest({:<10}) = {}\n", label_by_id(u), ans);
225 assert(ans == brute);
226 }
227
228 std::cout << std::format("\nActivate new team at Village-10\n");
229 activate(cd.id_of(n10));
230
231 for (Node * node : { n2, n6, n9, n10 })
232 {
233 const size_t u = cd.id_of(node);
234 const size_t ans = query(u);
235 const size_t brute = brute_query(u);
236 std::cout << std::format(" nearest({:<10}) = {}\n", label_by_id(u), ans);
237 assert(ans == brute);
238 }
239
240 std::cout << std::format("\nAll assertions passed.\n");
241 return 0;
242}
Heavy-Light and Centroid decomposition on rooted trees represented as Aleph graphs.
WeightedDigraph::Node Node
int main()
Demonstrates centroid-decomposition-based dynamic nearest-center queries on a fixed tree.
static Array create(size_t n)
Create an array with n logical elements.
Definition tpl_array.H:194
Centroid decomposition over a rooted tree represented as an Aleph graph.
size_t centroid_root_id() const noexcept
Root centroid ID of the centroid tree (or NONE if empty).
void for_each_centroid_ancestor_id(const size_t node, F &&f) const
Visit each centroid ancestor of node ID.
size_t id_of(const Node *node) const
Heavy-Light Decomposition over a rooted tree represented as an Aleph graph.
Graph implemented with double-linked adjacency lists.
Definition tpl_graph.H:428
virtual Node * insert_node(Node *node) noexcept
Insertion of a node already allocated.
Definition tpl_graph.H:524
_Graph_Node Node
The graph type.
Definition tpl_graph.H:432
Arc * insert_arc(Node *src_node, Node *tgt_node, void *a)
Definition tpl_graph.H:604
Main namespace for Aleph-w library functions.
Definition ah-arena.H:89
Divide_Conquer_DP_Result< Cost > divide_and_conquer_partition_dp(const size_t groups, const size_t n, Transition_Cost_Fn transition_cost, const Cost inf=dp_optimization_detail::default_inf< Cost >())
Optimize partition DP using divide-and-conquer optimization.
Arc of graph implemented with double-linked adjacency lists.
Definition tpl_graph.H:222
static int * k
Generic graph and digraph implementations.