157#include <tclap/CmdLine.h>
163using namespace Aleph;
177 cout <<
"\n" << string(60,
'=') <<
"\n";
178 cout <<
" " << title <<
"\n";
179 cout << string(60,
'=') <<
"\n\n";
184 cout <<
"\n--- " << title <<
" ---\n";
190 cout << label <<
":" <<
endl;
194 cout <<
" Vertices:" <<
endl;
195 for (
auto it = g.
get_node_it(); it.has_curr(); it.next())
197 auto node = it.get_curr();
198 cout <<
" " << node->get_info();
205 cout <<
" (degree=" << degree <<
")" <<
endl;
208 cout <<
" Edges:" <<
endl;
209 for (
auto it = g.
get_arc_it(); it.has_curr(); it.next())
211 auto arc = it.get_curr();
225 cout <<
"An Eulerian CYCLE visits every edge exactly once and returns to start.\n";
226 cout <<
"Condition (undirected): ALL vertices must have EVEN degree.\n\n";
240 cout <<
"\nAll vertices have degree 2 (even)." <<
endl;
243 cout <<
"Is Eulerian? " << (
test1(triangle) ?
"YES" :
"NO") <<
endl;
244 cout <<
"Eulerian cycle: A -> B -> C -> A" <<
endl;
264 cout <<
"\nAll vertices have degree 4 (even)." <<
endl;
267 cout <<
"Is Eulerian? " << (
test2(square) ?
"YES" :
"NO") <<
endl;
280 cout <<
"\nX has degree 1 (odd), Z has degree 1 (odd)." <<
endl;
283 cout <<
"Is Eulerian? " << (
test3(path) ?
"YES" :
"NO") <<
endl;
284 cout <<
"Cannot return to start without reusing edges." <<
endl;
295 cout <<
"The famous problem that started graph theory (Euler, 1736).\n\n";
296 cout <<
"Can you cross all 7 bridges exactly once and return to start?\n\n";
298 cout <<
"The city of Königsberg (now Kaliningrad) had:\n";
299 cout <<
" - 4 land masses (A, B, C, D)\n";
300 cout <<
" - 7 bridges connecting them\n\n";
329 cout <<
"Graph representation:" <<
endl;
330 cout <<
" Vertices (land masses): A, B, C, D" <<
endl;
331 cout <<
" Edges (bridges): 7" <<
endl;
332 cout <<
"\nDegrees:" <<
endl;
333 cout <<
" A: degree 5 (ODD)" <<
endl;
334 cout <<
" B: degree 3 (ODD)" <<
endl;
335 cout <<
" C: degree 3 (ODD)" <<
endl;
336 cout <<
" D: degree 3 (ODD)" <<
endl;
339 cout <<
"\nIs Eulerian (can return to start)? " << (
test(
konigsberg) ?
"YES" :
"NO") <<
endl;
341 cout <<
"\nEuler proved: With 4 odd-degree vertices, it's IMPOSSIBLE!\n";
342 cout <<
"For an Eulerian cycle, ALL vertices must have even degree.\n";
343 cout <<
"For an Eulerian path, exactly 0 or 2 vertices can have odd degree.\n";
354 cout <<
"For directed graphs, degree balance alone is not enough for an Eulerian cycle.\n";
355 cout <<
"Aleph-w checks in-degree/out-degree balance and also performs a reachability\n";
356 cout <<
"check among non-isolated vertices for cycle classification.\n\n";
362 auto d1 =
dcycle.insert_node(
"1");
363 auto d2 =
dcycle.insert_node(
"2");
364 auto d3 =
dcycle.insert_node(
"3");
365 dcycle.insert_arc(d1, d2, 1);
366 dcycle.insert_arc(d2, d3, 1);
367 dcycle.insert_arc(d3, d1, 1);
369 cout <<
"Directed cycle: 1 -> 2 -> 3 -> 1" <<
endl;
370 cout <<
" Node 1: in=1, out=1" <<
endl;
371 cout <<
" Node 2: in=1, out=1" <<
endl;
372 cout <<
" Node 3: in=1, out=1" <<
endl;
387 cout <<
"Directed path: A -> B -> C" <<
endl;
388 cout <<
" Node A: in=0, out=1 (UNBALANCED)" <<
endl;
389 cout <<
" Node B: in=1, out=1" <<
endl;
390 cout <<
" Node C: in=1, out=0 (UNBALANCED)" <<
endl;
399 auto f1 =
fig8.insert_node(
"Center");
400 auto f2 =
fig8.insert_node(
"Top");
401 auto f3 =
fig8.insert_node(
"Bottom");
403 fig8.insert_arc(f1, f2, 1);
404 fig8.insert_arc(f2, f1, 1);
406 fig8.insert_arc(f1, f3, 1);
407 fig8.insert_arc(f3, f1, 1);
409 cout <<
"Figure-8 shape:" <<
endl;
410 cout <<
" Center: in=2, out=2" <<
endl;
411 cout <<
" Top: in=1, out=1" <<
endl;
412 cout <<
" Bottom: in=1, out=1" <<
endl;
415 cout <<
"\nIs Eulerian? " << (
dtest3(
fig8) ?
"YES" :
"NO") <<
endl;
429 cout <<
"A mail carrier wants to visit every street exactly once.\n";
430 cout <<
"This is the Eulerian path/cycle problem!\n\n";
453 cout <<
"\nPerfect! The mail carrier can visit every street exactly once\n"
454 <<
"and return to the post office!\n";
456 cout <<
"\nSome streets must be visited more than once.\n";
461 cout <<
"Draw all connections without lifting the pen?\n";
462 cout <<
"This is an Eulerian path problem!\n\n";
477 cout <<
"Circuit with 5 connections:" <<
endl;
478 cout <<
" Pin1-Pin2, Pin2-Pin3, Pin3-Pin4, Pin4-Pin1, Pin1-Pin3" <<
endl;
482 for (
auto it =
circuit.get_node_it(); it.has_curr(); it.next())
493 cout <<
"Can draw all connections returning to start (Eulerian cycle)!\n";
495 cout <<
"Can draw all connections but not return to start (Eulerian path).\n";
497 cout <<
"Cannot draw without lifting pen - need " << (
odd_count/2) <<
" extra strokes.\n";
506 print_section(
"HIERHOLZER'S ALGORITHM: Finding Eulerian Paths");
508 cout <<
"Hierholzer's algorithm constructs an Eulerian path/cycle in O(E) time.\n";
509 cout <<
"Instead of just testing existence, it finds the actual path!\n\n";
525 cout <<
"Triangle graph: A-B-C\n";
526 cout <<
"Classification: ";
528 case Eulerian_Type::Cycle: cout <<
"EULERIAN CYCLE\n";
break;
529 case Eulerian_Type::Path: cout <<
"EULERIAN PATH\n";
break;
530 case Eulerian_Type::None: cout <<
"NOT EULERIAN\n";
break;
533 cout <<
"Path found (" <<
result1.path.size() <<
" edges):\n ";
537 for (
auto node :
nodes1) {
538 if (!first) cout <<
" -> ";
539 cout << node->get_info();
559 cout <<
"Linear path: 1-2-3-4\n";
560 cout <<
"Classification: ";
562 case Eulerian_Type::Cycle: cout <<
"EULERIAN CYCLE\n";
break;
563 case Eulerian_Type::Path: cout <<
"EULERIAN PATH\n";
break;
564 case Eulerian_Type::None: cout <<
"NOT EULERIAN\n";
break;
567 if (
result2.type != Eulerian_Type::None) {
568 cout <<
"Path found (" <<
result2.path.size() <<
" edges):\n ";
571 for (
auto node :
nodes2) {
572 if (!first) cout <<
" -> ";
573 cout << node->get_info();
580 print_subsection(
"Example 3: Bow-tie graph (two triangles sharing a vertex)");
601 cout <<
"Bow-tie: Two triangles sharing 'Center'\n";
602 cout <<
" Center has degree 4 (even)\n";
603 cout <<
" All others have degree 2 (even)\n";
604 cout <<
"Classification: ";
606 case Eulerian_Type::Cycle: cout <<
"EULERIAN CYCLE\n";
break;
607 case Eulerian_Type::Path: cout <<
"EULERIAN PATH\n";
break;
608 case Eulerian_Type::None: cout <<
"NOT EULERIAN\n";
break;
611 cout <<
"Path found (" <<
result3.path.size() <<
" edges):\n ";
614 for (
auto node :
nodes3) {
615 if (!first) cout <<
" -> ";
616 cout << node->get_info();
621 cout <<
"\nHierholzer's algorithm visits both triangles, returning to start!\n";
632 cout <<
"The compute() method returns detailed classification:\n";
633 cout <<
" - Eulerian_Type::Cycle - Has Eulerian cycle\n";
634 cout <<
" - Eulerian_Type::Path - Has Eulerian path but not cycle\n";
635 cout <<
" - Eulerian_Type::None - Not Eulerian\n\n";
647 TestCase t1{
"Triangle", {}, {{
"A",
"B"},{
"B",
"C"},{
"C",
"A"}}};
649 TestCase t2{
"Path 1-2-3", {}, {{
"1",
"2"},{
"2",
"3"}}};
651 TestCase t3{
"Star", {}, {{
"C",
"1"},{
"C",
"2"},{
"C",
"3"},{
"C",
"4"}}};
657 cout << setw(20) <<
"Graph" << setw(15) <<
"Result" << setw(20) <<
"has_eulerian_path()" <<
endl;
658 cout << string(55,
'-') <<
endl;
663 for (
auto& [u, v] :
tc.edges) {
664 if (node_map.find(u) == node_map.end())
666 if (node_map.find(v) == node_map.end())
667 node_map[v] =
tc.g.insert_node(v);
668 tc.g.insert_arc(node_map[u], node_map[v], 1);
676 case Eulerian_Type::Cycle:
result_str =
"CYCLE";
break;
677 case Eulerian_Type::Path:
result_str =
"PATH";
break;
678 case Eulerian_Type::None:
result_str =
"NONE";
break;
681 cout << setw(20) <<
tc.name
683 << setw(20) << (
tester.has_eulerian_path(
tc.g) ?
"true" :
"false") <<
endl;
696 "Eulerian graph example for Aleph-w.\n"
697 "Demonstrates Eulerian path and cycle detection.",
703 "Run specific section: cycle, konigsberg, directed, practical, hierholzer, types, or 'all'",
704 false,
"all",
"section",
cmd
712 cout <<
"============================================================\n";
713 cout <<
" ALEPH-W EULERIAN GRAPHS EXAMPLE\n";
714 cout <<
"============================================================\n";
734 cout <<
"\n" << string(60,
'=') <<
"\n";
735 cout <<
"Eulerian graphs demo completed!\n";
736 cout << string(60,
'=') <<
"\n\n";
740 catch (TCLAP::ArgException& e)
742 cerr <<
"Error: " << e.error() <<
" for argument " << e.argId() <<
endl;
747 cerr <<
"Error: " << e.what() <<
endl;
Generic directed graph (digraph) wrapper template.
void next()
Advances the iterator to the next filtered element.
Finds and constructs an Eulerian path or cycle using Hierholzer's algorithm.
Graph implemented with double-linked adjacency lists.
virtual Node * insert_node(Node *node) noexcept
Insertion of a node already allocated.
Arc * insert_arc(Node *src_node, Node *tgt_node, void *a)
Tests whether a graph or digraph is Eulerian.
Eulerian_Type compute(GT &g)
Compute detailed Eulerian classification.
auto get_arc_it() const noexcept
Obtains an iterator to the arc of graph.
Node * get_src_node(Arc *arc) const noexcept
Return the source node of arc (only for directed graphs)
constexpr size_t get_num_nodes() const noexcept
Return the total of nodes of graph.
constexpr size_t get_num_arcs() const noexcept
auto get_node_it() const noexcept
Obtains an iterator to the nodes of graph.
Node * get_tgt_node(Arc *arc) const noexcept
Return the target node of arc (only for directed graphs)
Eulerian graph detection and path/cycle finding.
void print_subsection(const string &title)
void demo_eulerian_type()
void print_section(const string &title)
void print_graph(const string &label, G &g)
void demo_eulerian_cycle()
Main namespace for Aleph-w library functions.
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.
static void section(const string &title)
Arc of graph implemented with double-linked adjacency lists.
Node belonging to a graph implemented with a double linked adjacency list.
Filtered iterator of adjacent arcs of a node.
Generic graph and digraph implementations.