snippets 0.1.0
Loading...
Searching...
No Matches
graph.hpp
Go to the documentation of this file.
1#ifndef GRAPH_H
2#define GRAPH_H
3
4#include <functional>
5#include <vector>
6#include <optional>
7#include <queue>
8#include <stack>
9#include <cassert>
10#include <unordered_set>
11#include <unordered_map>
12
13namespace hsc_snippets
14{
27 static std::vector<std::vector<std::pair<int, int>>> make_weighted_directed_adjacency_list(int n, const std::vector<std::vector<int>> &edges)
28 {
29 auto adjacency_list = std::vector<std::vector<std::pair<int, int>>>(n);
30 for (auto &&edge : edges)
31 {
32 int from = edge[0];
33 int to = edge[1];
34 int weight = edge[2];
35 adjacency_list[from].emplace_back(to, weight);
36 }
37 return adjacency_list;
38 }
39
52 static std::vector<std::vector<int>> make_unweighted_undirected_adjacency_list(int n, const std::vector<std::vector<int>> &edges)
53 {
54 auto adjacency_list = std::vector<std::vector<int>>(n);
55 for (auto &&edge : edges)
56 {
57 int from = edge[0];
58 int to = edge[1];
59 adjacency_list[from].push_back(to);
60 adjacency_list[to].push_back(from); // For undirected graph, edges are bidirectional
61 }
62 return adjacency_list;
63 }
64
77 static std::vector<std::vector<std::pair<int, int>>> make_weighted_undirected_adjacency_list(int n, const std::vector<std::vector<int>> &edges)
78 {
79 auto adjacency_list = std::vector<std::vector<std::pair<int, int>>>(n);
80 for (auto &&edge : edges)
81 {
82 int from = edge[0];
83 int to = edge[1];
84 int weight = edge[2];
85 adjacency_list[from].emplace_back(to, weight);
86 adjacency_list[to].emplace_back(from, weight); // For undirected graph, edges are bidirectional
87 }
88 return adjacency_list;
89 }
90
103 static std::vector<std::vector<int>> make_unweighted_directed_adjacency_list(int n, const std::vector<std::vector<int>> &edges)
104 {
105 auto adjacency_list = std::vector<std::vector<int>>(n);
106 for (auto &&edge : edges)
107 {
108 int from = edge[0];
109 int to = edge[1];
110 adjacency_list[from].push_back(to);
111 }
112 return adjacency_list;
113 }
114
126 static void breadth_first_search(std::vector<std::vector<int>> &adjacency_list, int root, std::function<void(int, int)> callback)
127 {
128 auto visited = std::unordered_set<int>{};
129 auto q = std::queue<std::pair<int, int>>{}; // Regular queue for BFS
130 q.emplace(0, root); // Initialize queue with root node at distance 0
131 while (!q.empty())
132 {
133 auto [dist, node] = q.front(); // Extract node at the front of the queue
134 q.pop();
135
136 if (visited.contains(node)) // Skip if node has already been visited
137 {
138 continue;
139 }
140 visited.insert(node); // Mark current node as visited
141
142 callback(dist, node); // Invoke callback for the current node
143
144 for (auto adjacent_node : adjacency_list[node]) // Explore adjacent nodes
145 {
146 if (visited.contains(adjacent_node)) // Skip if adjacent node has already been visited
147 {
148 continue;
149 }
150 q.emplace(dist + 1, adjacent_node); // Enqueue adjacent node with distance incremented by 1
151 }
152 }
153 }
164 static void breadth_first_search(std::unordered_map<int, std::vector<int>> &adjacency_list, int root, std::function<void(int, int)> callback)
165 {
166 auto visited = std::unordered_set<int>{};
167 auto q = std::queue<std::pair<int, int>>{}; // Regular queue for BFS
168 q.emplace(0, root); // Initialize queue with root node at distance 0
169 while (!q.empty())
170 {
171 auto [dist, node] = q.front(); // Extract node at the front of the queue
172 q.pop();
173
174 if (visited.contains(node)) // Skip if node has already been visited
175 {
176 continue;
177 }
178 visited.insert(node); // Mark current node as visited
179
180 callback(dist, node); // Invoke callback for the current node
181
182 for (auto adjacent_node : adjacency_list[node]) // Explore adjacent nodes
183 {
184 if (visited.contains(adjacent_node)) // Skip if adjacent node has already been visited
185 {
186 continue;
187 }
188 q.emplace(dist + 1, adjacent_node); // Enqueue adjacent node with distance incremented by 1
189 }
190 }
191 }
192
204 static void depth_first_search(std::vector<std::vector<int>> &adjacency_list, int root, std::function<void(int, int)> callback)
205 {
206 auto visited = std::unordered_set<int>{};
207 auto stack = std::stack<std::pair<int, int>>{}; // Stack for DFS
208 stack.emplace(0, root); // Initialize stack with root node at distance 0
209 while (!stack.empty())
210 {
211 auto [dist, node] = stack.top(); // Extract node at the top of the stack
212 stack.pop();
213
214 if (visited.contains(node)) // Skip if node has already been visited
215 {
216 continue;
217 }
218 visited.insert(node); // Mark current node as visited
219
220 callback(dist, node); // Invoke callback for the current node
221
222 for (auto adjacent_node : adjacency_list[node]) // Explore adjacent nodes
223 {
224 if (visited.contains(adjacent_node)) // Skip if adjacent node has already been visited
225 {
226 continue;
227 }
228 stack.emplace(dist + 1, adjacent_node); // Push adjacent node with distance incremented by 1
229 }
230 }
231 }
232
242 static int dijkstra(int n, const std::vector<std::vector<std::pair<int, int>>> &adjacency_list, int src, int dst)
243 {
244
245 std::vector<int> dist(n, std::numeric_limits<int>::max());
246 std::priority_queue<std::pair<int, int>, std::vector<std::pair<int, int>>, std::greater<>> pq;
247
248 dist[src] = 0;
249 pq.emplace(0, src);
250
251 while (!pq.empty())
252 {
253 int u = pq.top().second;
254 pq.pop();
255
256 for (const auto &neighbor : adjacency_list[u])
257 {
258 int v = neighbor.first;
259 int weight = neighbor.second;
260
261 if (dist[v] > dist[u] + weight)
262 {
263 dist[v] = dist[u] + weight;
264 pq.emplace(dist[v], v);
265 }
266 }
267 }
268
269 return dist[dst] == std::numeric_limits<int>::max() ? -1 : dist[dst];
270 }
271
289 static std::vector<int> find_euler_path_directed(const std::vector<std::vector<int>> &edges)
290 {
291 std::unordered_map<int, std::stack<int>> adj;
292 std::unordered_map<int, int> in;
293 std::unordered_map<int, int> out;
294 for (auto &&edge : edges)
295 {
296 int from = edge[0];
297 int to = edge[1];
298 adj[from].push(to);
299 in[to] += 1;
300 out[from] += 1;
301 }
302
303 int start = adj.begin()->first; // Default start node
304 for (auto &&p : adj)
305 {
306 if (out[p.first] - in[p.first] == 1)
307 { // Find the actual start node for Euler Path
308 start = p.first;
309 break;
310 }
311 }
312
313 std::stack<int> current_path;
314 std::vector<int> circuit;
315 current_path.push(start);
316
317 while (!current_path.empty())
318 {
319 int current_vertex = current_path.top();
320
321 if (!adj[current_vertex].empty())
322 { // If current vertex has neighbors
323 int next_vertex = adj[current_vertex].top();
324 adj[current_vertex].pop(); // Remove the edge from current to next
325 current_path.push(next_vertex); // Move to next vertex
326 }
327 else
328 { // Backtrack
329 circuit.push_back(current_vertex); // Add to Euler circuit/path
330 current_path.pop(); // Remove the vertex as it has no more neighbors
331 }
332 }
333
334 // Reverse the circuit to get the Euler path
335 std::reverse(circuit.begin(), circuit.end());
336
337 return circuit;
338 }
339
350 static std::vector<std::vector<int>> find_connected_components(std::unordered_map<int, std::vector<int>> &adj)
351 {
352 std::unordered_map<int, bool> visited{}; // Tracks whether each node has been visited
353 for (auto &&p : adj)
354 {
355 visited.insert({p.first, false}); // Initialize all nodes as unvisited
356 }
357
358 std::vector<std::vector<int>> connectedComponents; // Stores the connected components
359
360 for (auto &&p : visited)
361 {
362 if (!p.second)
363 { // For each unvisited node
364 std::vector<int> component; // Stores the current component's nodes
365 breadth_first_search(adj, p.first, [&visited, &component](int, int node)
366 {
367 visited[node] = true; // Mark the node as visited
368 component.push_back(node); // Add the node to the current component
369 }); // Perform BFS to find all nodes in this component
370 connectedComponents.push_back(component); // Add the current component to the list
371 }
372 }
373
374 return connectedComponents; // Return all found connected components
375 }
376
377
385 static int count_connected_components(const std::unordered_map<int, std::vector<int>> &adj)
386 {
387 std::unordered_set<int> visited;
388 int component_count = 0;
389
390 auto dfs = [&](int node, auto &dfs_ref) -> void {
391 visited.insert(node);
392 for (int neighbor : adj.at(node))
393 {
394 if (visited.find(neighbor) == visited.end())
395 {
396 dfs_ref(neighbor, dfs_ref);
397 }
398 }
399 };
400
401 for (const auto &p : adj)
402 {
403 int node = p.first;
404 if (visited.find(node) == visited.end())
405 {
406 // Start a DFS from the unvisited node
407 dfs(node, dfs);
408 // After DFS, we've explored an entire connected component
409 component_count++;
410 }
411 }
412
413 return component_count;
414 }
415
416}
417
418#endif // GRAPH_H
Definition big_integer.hpp:14
static int dijkstra(int n, const std::vector< std::vector< std::pair< int, int > > > &adjacency_list, int src, int dst)
Definition graph.hpp:242
static std::vector< std::vector< int > > find_connected_components(std::unordered_map< int, std::vector< int > > &adj)
Definition graph.hpp:350
static std::vector< std::vector< int > > make_unweighted_directed_adjacency_list(int n, const std::vector< std::vector< int > > &edges)
Definition graph.hpp:103
static std::vector< std::vector< std::pair< int, int > > > make_weighted_directed_adjacency_list(int n, const std::vector< std::vector< int > > &edges)
Definition graph.hpp:27
static std::vector< std::vector< std::pair< int, int > > > make_weighted_undirected_adjacency_list(int n, const std::vector< std::vector< int > > &edges)
Definition graph.hpp:77
static int count_connected_components(const std::unordered_map< int, std::vector< int > > &adj)
Definition graph.hpp:385
static void depth_first_search(std::vector< std::vector< int > > &adjacency_list, int root, std::function< void(int, int)> callback)
Definition graph.hpp:204
static std::vector< int > find_euler_path_directed(const std::vector< std::vector< int > > &edges)
Definition graph.hpp:289
static void breadth_first_search(std::vector< std::vector< int > > &adjacency_list, int root, std::function< void(int, int)> callback)
Definition graph.hpp:126
static std::vector< std::vector< int > > make_unweighted_undirected_adjacency_list(int n, const std::vector< std::vector< int > > &edges)
Definition graph.hpp:52