diff --git a/CPP/algorithms/graph_algorithms/hierholzer_algorithm.cpp b/CPP/algorithms/graph_algorithms/hierholzer_algorithm.cpp new file mode 100644 index 00000000..62d883a6 --- /dev/null +++ b/CPP/algorithms/graph_algorithms/hierholzer_algorithm.cpp @@ -0,0 +1,124 @@ +/* + * Algorithm: Hierholzer’s Algorithm (Eulerian Path / Circuit) + * + * Problem: + * Given a connected graph (directed or undirected), find an Eulerian Path or Circuit. + * - Eulerian Path: visits every edge exactly once. + * - Eulerian Circuit: Eulerian Path that starts and ends on the same vertex. + * + * Eulerian Path Conditions: + * - Undirected: At most 2 vertices have odd degree. + * - Directed: exactly 1 vertex has (out = in + 1), exactly 1 has (in = out + 1), + * all others: indegree == outdegree. + * + * Eulerian Circuit Conditions: + * - Undirected: all vertices have even degree. + * - Directed: indegree == outdegree for every vertex. + * + * Approach (Hierholzer’s Algorithm): + * 1. Pick starting vertex: + * - Circuit → any vertex. + * - Path → vertex with (outdeg > indeg). + * 2. Traverse edges using a stack, removing them as you go. + * 3. If stuck, backtrack → add vertex to final path. + * 4. Reverse final path → Eulerian Path / Circuit. + * + * Complexity: + * - O(E), since each edge is used exactly once. + */ + +#include +using namespace std; + +class Eulerian +{ +public: + vector findEulerianPath(int n, vector> &edges) + { + vector> adj(n); + vector indeg(n, 0), outdeg(n, 0); + + // Build adjacency list + for (auto &e : edges) + { + int u = e[0], v = e[1]; + adj[u].push_back(v); + outdeg[u]++; + indeg[v]++; + } + + // Find start node (for path vs circuit) + int start = 0; + for (int i = 0; i < n; i++) + { + if (outdeg[i] - indeg[i] == 1) + start = i; // Eulerian path start + } + + vector path, stack = {start}; + + // Hierholzer’s Algorithm + while (!stack.empty()) + { + int u = stack.back(); + if (!adj[u].empty()) + { + // Go deeper using available edge + int v = adj[u].back(); + adj[u].pop_back(); // remove edge u→v + stack.push_back(v); + + // 🔎 Visualization step + // cout << "Traverse edge " << u << " -> " << v << endl; + } + else + { + // No more edges → add to path (backtrack) + path.push_back(u); + stack.pop_back(); + + // 🔎 Visualization step + // cout << "Backtrack: add " << u << " to path" << endl; + } + } + + reverse(path.begin(), path.end()); // final path + return path; + } +}; + +int main() +{ + // Example Graph: Eulerian Circuit + int n = 4; + vector> edges = { + {0, 1}, {1, 2}, {2, 0}, {0, 3}, {3, 0}}; + + Eulerian solver; + vector path = solver.findEulerianPath(n, edges); + + cout << "Eulerian Path/Circuit: "; + for (int v : path) + cout << v << " "; + cout << endl; + + /* + * Visualization for this graph: + * + * Edges: 0->1, 1->2, 2->0, 0->3, 3->0 + * + * Step walk: + * Start at 0 + * 0 -> 3 + * 3 -> 0 + * 0 -> 1 + * 1 -> 2 + * 2 -> 0 + * + * Backtracking order: + * 0 (dead end) → 2 → 1 → 0 → 3 → 0 + * + * Final Eulerian Circuit: + * 0 → 3 → 0 → 1 → 2 → 0 + */ +} diff --git a/CPP/algorithms/graph_algorithms/prims_algorithm.cpp b/CPP/algorithms/graph_algorithms/prims_algorithm.cpp new file mode 100644 index 00000000..58545d07 --- /dev/null +++ b/CPP/algorithms/graph_algorithms/prims_algorithm.cpp @@ -0,0 +1,145 @@ +// Prim’s Algorithm — Minimum Spanning Tree (MST) +// Problem +// Given a weighted, undirected graph, find a subset of edges +// that connects all vertices with minimum total weight without cycles. +// +// Approach +// 1. Start from any vertex (usually 0), mark it as part of MST. +// 2. Use a priority queue (min-heap) to pick the smallest edge +// connecting MST to a new vertex. +// 3. Add the chosen vertex to MST and repeat until all vertices included. +// +// Complexity +// Time : O((V + E) log V) — using priority queue +// Space : O(V + E) — adjacency list + key array + heap +// +// Input +// - Number of vertices (V) +// - Number of edges (E) +// - Edge list {u, v, w} (u ↔ v with weight w) +// +// Output +// - Total weight of MST +// - Edges included in MST + +#include +#include +#include +#include +using namespace std; + +int main() +{ + ios::sync_with_stdio(false); + cin.tie(nullptr); + + int V, E; + cin >> V >> E; + vector>> adj(V); + + + for (int i = 0; i < E; i++) + { + int u, v, w; + cin >> u >> v >> w; + adj[u].push_back({v, w}); + adj[v].push_back({u, w}); // undirected graph + } + + const int INF = numeric_limits::max(); + vector key(V, INF); // minimum edge weight to MST + vector parent(V, -1); // store MST edges + vector inMST(V, false); // track vertices included + + priority_queue, vector>, greater<>> pq; + + int start = 0; + key[start] = 0; + pq.push({0, start}); + + while (!pq.empty()) + { + int w = pq.top().first; + int u = pq.top().second; + pq.pop(); + if (inMST[u]) + continue; + + inMST[u] = true; + + for (auto &edge : adj[u]) + { + int v = edge.first, weight = edge.second; + if (!inMST[v] && weight < key[v]) + { + key[v] = weight; + parent[v] = u; + pq.push({key[v], v}); + } + } + } + + int totalWeight = 0; + cout << "Edges in MST:\n"; + for (int v = 0; v < V; v++) + { + if (parent[v] != -1) + { + cout << parent[v] << " - " << v << " (weight " << key[v] << ")\n"; + totalWeight += key[v]; + } + } + cout << "Total MST weight: " << totalWeight << "\n"; + + return 0; +} + +/* +Example Input: +5 7 +0 1 2 +0 3 6 +1 2 3 +1 3 8 +1 4 5 +2 4 7 +3 4 9 + +Visualization: +Graph: + (2) + 0 ------- 1 + \ /|\ + (6)\ (3)(5) + \ / \ + 3 4 + (9) (7) + +Step-by-step Execution: +Start from 0: +- Include 0 → candidate edges: 0→1(2), 0→3(6) +- Pick min edge 0→1(2) → add 1 +- Candidate edges: 1→2(3), 1→3(8), 1→4(5), 0→3(6) +- Pick min edge 1→2(3) → add 2 +- Candidate edges: 1→3(8), 1→4(5), 2→4(7), 0→3(6) +- Pick min edge 1→4(5) → add 4 +- Candidate edges: 0→3(6), 1→3(8), 2→4(7), 3→4(9) +- Pick min edge 0→3(6) → add 3 +All vertices included → MST complete + +MST edges: +0 - 1 (2) +1 - 2 (3) +1 - 4 (5) +0 - 3 (6) +Total MST weight: 16 + +Time : O((V+E) log V) +Space : O(V+E) +*/ + +// add: Prim PR + +// prepare Prim PR + +// prepare PR