133using namespace Aleph;
159 for (
auto it = g.get_node_it(); it.has_curr(); it.next())
160 if (it.get_curr()->get_info() == name)
161 return it.get_curr();
167 cout <<
"Graph structure:\n";
168 for (
auto nit = g.get_node_it();
nit.has_curr();
nit.next())
170 auto* node =
nit.get_curr();
171 cout <<
" " << node->get_info() <<
" → ";
173 for (
auto ait = g.get_out_it(node);
ait.has_curr();
ait.next())
175 auto* arc =
ait.get_curr();
176 auto* tgt = g.get_tgt_node(arc);
177 if (!first)
cout <<
", ";
178 cout << tgt->get_info() <<
"(" << arc->get_info() <<
")";
188 if (path.
size() == 0)
190 cout <<
"(no path)\n";
197 if (!first)
cout <<
" → ";
198 cout << n->get_info();
201 cout <<
"\n Edges: ";
205 if (!first)
cout <<
" + ";
206 cout << a->get_info();
207 total += a->get_info();
213template <
typename Func>
216 auto start = chrono::high_resolution_clock::now();
218 auto end = chrono::high_resolution_clock::now();
219 return chrono::duration<double, milli>(end - start).count();
228 cout <<
"━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n";
229 cout <<
"Example 1: Shortest Paths with Negative Weights\n";
230 cout <<
"━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n\n";
248 auto* A = g.insert_node(
"A");
249 auto*
B = g.insert_node(
"B");
250 auto* C = g.insert_node(
"C");
251 auto*
D = g.insert_node(
"D");
252 auto* E = g.insert_node(
"E");
254 g.insert_arc(A,
B, 4.0);
255 g.insert_arc(A, C, 2.0);
256 g.insert_arc(
B, E, 3.0);
257 g.insert_arc(C,
B, -2.0);
258 g.insert_arc(C,
D, 1.0);
260 cout <<
"Graph with negative edge C→B (-2):\n\n";
263 cout <<
"\n▶ Running Bellman-Ford from A:\n\n";
266 bool has_negative_cycle =
bf.paint_spanning_tree(A);
268 if (has_negative_cycle)
270 cout <<
" ERROR: Negative cycle detected!\n";
274 cout <<
" No negative cycle detected.\n\n";
277 cout <<
" Distances from A:\n";
278 for (
auto it = g.get_node_it(); it.has_curr(); it.next())
280 auto* node = it.get_curr();
281 double dist =
bf.get_distance(node);
282 cout <<
" A → " << node->get_info() <<
": ";
284 if (dist == numeric_limits<double>::max())
285 cout <<
"∞ (unreachable)\n";
287 cout << dist <<
"\n";
291 cout <<
"\n Path A → E:\n ";
293 bf.get_min_path(E, path);
296 cout <<
"\n Note: Dijkstra would fail here because of the negative edge!\n";
305 cout <<
"\n━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n";
306 cout <<
"Example 2: Negative Cycle Detection\n";
307 cout <<
"━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n\n";
325 auto* A = g.insert_node(
"A");
326 auto*
B = g.insert_node(
"B");
327 auto* C = g.insert_node(
"C");
329 g.insert_arc(A,
B, 1.0);
330 g.insert_arc(
B, C, 2.0);
331 g.insert_arc(C, A, -5.0);
333 cout <<
"Graph with negative cycle (A→B→C→A has weight -2):\n\n";
336 cout <<
"\n▶ Running Bellman-Ford from A:\n\n";
339 bool has_negative_cycle =
bf.paint_spanning_tree(A);
341 if (has_negative_cycle)
343 cout <<
" ⚠ NEGATIVE CYCLE DETECTED!\n\n";
344 cout <<
" When a negative cycle exists, shortest paths are undefined\n";
345 cout <<
" because you can always go around the cycle to decrease the cost.\n";
350 cout <<
"\n Negative cycle: ";
352 cout << n->get_info() <<
" → ";
364 cout <<
" No negative cycle detected.\n";
374 cout <<
"\n━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n";
375 cout <<
"Example 3: Standard vs SPFA (Faster) Variant\n";
376 cout <<
"━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n\n";
378 cout <<
"SPFA (Shortest Path Faster Algorithm) is a queue-based optimization\n";
379 cout <<
"of Bellman-Ford. It only relaxes edges from nodes whose distances\n";
380 cout <<
"have been updated, which is often much faster in practice.\n\n";
387 for (
int i = 0; i <
N; ++i)
391 for (
int i = 0; i <
N; ++i)
394 if (i + 1 <
N) g.insert_arc(
nodes[i],
nodes[i + 1], 1.0);
395 if (i + 2 <
N) g.insert_arc(
nodes[i],
nodes[i + 2], 3.0);
396 if (i + 5 <
N) g.insert_arc(
nodes[i],
nodes[i + 5], 4.0);
399 if (i > 0 && i % 10 == 0)
403 cout <<
"Graph: " << g.get_num_nodes() <<
" nodes, " << g.get_num_arcs() <<
" arcs\n\n";
410 bf.paint_spanning_tree(
nodes[0]);
421 bf.faster_paint_spanning_tree(
nodes[0]);
429 cout <<
"\n Note: SPFA is usually faster on sparse graphs, but has the\n";
430 cout <<
" same worst-case complexity O(V*E) as standard Bellman-Ford.\n";
439 cout <<
"\n━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n";
440 cout <<
"Example 4: When to Use Bellman-Ford vs Dijkstra\n";
441 cout <<
"━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n\n";
444┌──────────────────────────────────────────────────────────────────────┐
445│ Algorithm Selection Guide │
446├──────────────────────────────────────────────────────────────────────┤
447│ Criterion │ Dijkstra │ Bellman-Ford │
448├────────────────────────┼─────────────────┼──────────────────────────┤
449│ Edge weights │ Non-negative │ Any (incl. negative) │
450│ Time complexity │ O((V+E) log V) │ O(V × E) │
451│ Negative cycle detect │ No │ Yes │
452│ Best for │ Road networks │ Currency exchange, │
453│ │ GPS routing │ game AI, financial │
454├────────────────────────┴─────────────────┴──────────────────────────┤
455│ Use Bellman-Ford when: │
456│ • Graph has negative edge weights │
457│ • Need to detect negative cycles │
458│ • Correctness more important than speed │
460│ Use Dijkstra when: │
461│ • All edges are non-negative │
462│ • Performance is critical │
463│ • Working with large road/network graphs │
464└──────────────────────────────────────────────────────────────────────┘
474 cout <<
"Usage: " <<
prog <<
" [--negative-cycles] [--spfa] [--help]\n";
475 cout <<
"\nIf no flags are given, all demos are executed.\n";
480 for (
int i = 1; i <
argc; ++i)
481 if (std::strcmp(
argv[i], flag) == 0)
488 cout <<
"╔══════════════════════════════════════════════════════════════════════╗\n";
489 cout <<
"║ Bellman-Ford Algorithm - Comprehensive Example ║\n";
490 cout <<
"╚══════════════════════════════════════════════════════════════════════╝\n\n";
Bellman-Ford algorithm for single-source shortest paths.
void example_comparison_dijkstra()
Node * find_node(WeightedDigraph &g, const string &name)
void print_graph(WeightedDigraph &g)
void example_basic_negative_weights()
WeightedDigraph::Node Node
static void usage(const char *prog)
static bool has_flag(int argc, char *argv[], const char *flag)
void example_spfa_comparison()
void print_path(Path< WeightedDigraph > &path, WeightedDigraph &g)
void example_negative_cycle()
double measure_ms(Func &&f)
Bellman-Ford algorithm for shortest paths with negative weights.
Generic directed graph (digraph) wrapper template.
typename BaseGraph::Arc Arc
typename BaseGraph::Node Node
void for_each_node(Operation op=Operation()) const
Execute an operation on each node of path.
size_t size() const noexcept
Return the path length in nodes.
void for_each_arc(Operation op=Operation()) const
Execute an operation on each arc of path.
DynArray< Graph::Node * > nodes
Main namespace for Aleph-w library functions.
std::string to_string(const time_t t, const std::string &format)
Format a time_t value into a string using format.
DynList< T > maps(const C &c, Op op)
Classic map operation.
Arc of graph implemented with double-linked adjacency lists.
static void set_zero(Arc *a)
Distance_Type operator()(Arc *a) const
Generic graph and digraph implementations.