0% found this document useful (0 votes)
17 views

Graph Algorithms Study Guide

This study guide is designed to help users master graph algorithms for FAANG software engineering interviews, covering essential concepts, traversal techniques, shortest path algorithms, Minimum Spanning Trees, and more. It emphasizes building intuition behind algorithms, provides C++ implementations, and includes complexity analysis and practice problems. The guide also discusses graph representations, comparing adjacency matrices and lists, and offers insights into choosing the appropriate representation based on graph density and operational needs.

Uploaded by

Deepthi
Copyright
© © All Rights Reserved
Available Formats
Download as DOCX, PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
17 views

Graph Algorithms Study Guide

This study guide is designed to help users master graph algorithms for FAANG software engineering interviews, covering essential concepts, traversal techniques, shortest path algorithms, Minimum Spanning Trees, and more. It emphasizes building intuition behind algorithms, provides C++ implementations, and includes complexity analysis and practice problems. The guide also discusses graph representations, comparing adjacency matrices and lists, and offers insights into choosing the appropriate representation based on graph density and operational needs.

Uploaded by

Deepthi
Copyright
© © All Rights Reserved
Available Formats
Download as DOCX, PDF, TXT or read online on Scribd
You are on page 1/ 98

Graph Algorithms Study Guide - 1

Introduction
Purpose: This guide provides a comprehensive resource for mastering graph
algorithms, specifically tailored for tackling challenges encountered in FAANG
software engineering interviews. The objective is to build a deep, intuitive
understanding and practical proficiency, enabling confident problem-solving for any
graph-related question.

Scope: The study guide covers the essential spectrum of graph theory relevant to
technical interviews. It begins with fundamental concepts like graph definitions and
representations, progresses through core traversal techniques (BFS and DFS), delves
into shortest path algorithms (Dijkstra, Bellman-Ford, Floyd-Warshall), explores
Minimum Spanning Trees (Prim's, Kruskal's), and examines topological sorting, cycle
detection, connectivity analysis (including Strongly Connected Components), and the
crucial Union-Find data structure.

Approach: The focus is on building intuition – understanding the "why" behind each
algorithm's steps and its underlying assumptions. This is complemented by clear,
standard C++ implementations designed for readability and interview contexts.
Complexity analysis (time and space) is provided for each algorithm, a critical aspect
of interview discussions. Finally, curated practice problems from LeetCode,
prioritizing those likely encountered in FAANG interviews, are mapped to relevant
algorithms to solidify understanding and application skills.

I. Graph Fundamentals
A. Core Concepts
Graphs are mathematical structures used to model pairwise relationships between
objects.1 They are fundamental in computer science, representing diverse systems
like social networks, road maps, computer networks, and dependencies.3 Formally, a
graph G is defined as an ordered pair G = (V, E), where V is a set of vertices (also
called nodes or points) representing the entities, and E is a set of edges (also called
links or arcs) representing the connections or relationships between these vertices.1
● Vertices (Nodes): These are the basic units of a graph, often depicted as circles
or points. Each vertex typically represents an object, entity, or location.1
● Edges (Links): These represent the connections or relationships between pairs
of vertices, usually drawn as lines.1 An edge connecting vertices u and v can be
denoted as (u, v) or {u, v}.

Graphs can be categorized based on the nature of their edges:


● Directed vs. Undirected Graphs:
○ Undirected Graphs: Edges have no direction, signifying a symmetric or
bidirectional relationship. If vertex A is connected to vertex B, then B is also
connected to A. The edge {u, v} is identical to {v, u}.1 Example: Mutual
friendships on Facebook.
○ Directed Graphs (Digraphs): Edges have a specific direction, indicating an
asymmetric or unidirectional relationship. An edge (u, v) goes from u (tail) to v
(head). If A points to B, it doesn't imply B points to A.1 Example: Following
someone on Twitter.
● Weighted vs. Unweighted Graphs:
○ Weighted Graphs: Each edge has an associated numerical value, called a
weight or cost. This weight often represents distance, time, capacity, cost, or
strength of connection.1 Example: A road map where edge weights are
distances between cities.4
○ Unweighted Graphs: Edges do not have assigned weights, or all edges are
considered to have a uniform weight (often 1). These graphs model pure
connectivity.3 Example: A simple social network graph just showing
connections.

Other important terminology includes:


● Neighbors: Two vertices are neighbors if they are connected by an edge.7
● Degree: The degree of a vertex in an undirected graph is the number of edges
incident to it.6 In a directed graph, we distinguish between:
○ In-degree: The number of incoming edges to a vertex.3
○ Out-degree: The number of outgoing edges from a vertex.3 Understanding
vertex degrees is crucial for analyzing connectivity and identifying central
nodes within a network.6
● Path: A sequence of vertices where each adjacent pair is connected by an edge.3
A simple path has no repeated vertices.7
● Cycle: A path that starts and ends at the same vertex, containing at least one
edge.3 Graphs without cycles are called acyclic.4
● Simple Graph: An undirected graph with no loops (edges connecting a vertex to
itself) and no multiple edges between the same pair of vertices.1
● Multigraph: A graph that allows multiple edges between the same pair of
vertices.1

B. Graph Representations
To work with graphs computationally, we need ways to represent their structure in
memory. The two most common methods are the Adjacency Matrix and the
Adjacency List.3

1. Adjacency Matrix:
● Definition: An adjacency matrix represents a graph G = (V, E) as a V x V square
matrix (let's call it adjMat), where V is the number of vertices. The entry adjMat[i]
[j] is typically 1 (or the edge weight for weighted graphs) if there is an edge from
vertex i to vertex j, and 0 otherwise.3 For undirected graphs, the adjacency matrix
is symmetric (adjMat[i][j] == adjMat[j][i]) because an edge {i, j} implies
connections in both directions.4 For weighted graphs, non-edge entries are often
initialized to infinity (or a very large number) and diagonal entries (adjMat[i][i])
are 0.16
● C++ Implementation: A common way to implement this in C++ is using a vector
of vectors: vector<vector<int>> adjMatrix(V, vector<int>(V, 0)); for an unweighted
graph, or vector<vector<int>> adjMatrix(V, vector<int>(V, INF)); for a weighted
graph (initializing diagonals to 0 separately). Adding an edge (u, v) with weight w
involves adjMatrix[u][v] = w; (and adjMatrix[v][u] = w; if undirected).12 While
simple, vector<vector<int>> can have performance drawbacks due to multiple
memory allocations and potentially poor cache locality.14 Using a single
std::vector<int> data(V*V); and indexing with data[i * V + j] offers better memory
contiguity.14 C++23's std::mdspan provides a safer and more expressive way to
view this single vector as a 2D matrix.14 However, for typical interview settings,
vector<vector<int>> is often sufficient and understood.

// Adjacency Matrix Implementation for Unweighted Undirected Graphs

#include <vector>
#include <iostream>

using namespace std;


// Function to add an edge to the adjacency matrix.
// Takes the adjacency matrix, and two vertices u and v as input.
void addEdgeMatrix(vector<vector<int>>& adjMatrix, int u, int v) {
// Ensure vertices are within valid bounds of the matrix.
if (u >= 0 && u < adjMatrix.size() && v >= 0 && v <
adjMatrix.size()) {
adjMatrix[u][v] = 1;
adjMatrix[v][u] = 1; // For undirected graphs, the edge is
bidirectional.
}
}

// Function to output the adjacency matrix to the console.


// Takes the adjacency matrix as input.
void printMatrix(const vector<vector<int>>& adjMatrix) {
cout << "Adjacency Matrix:" << endl;
for (const auto& row : adjMatrix) {
for (int val : row) {
cout << val << " ";
}
cout << endl;
}
}

/* Example demonstration:
int main() {
int V = 5; // Number of vertices in the graph.
// Initialize a V x V matrix with all elements set to 0.
vector<vector<int>> adjMatrix(V, vector<int>(V, 0));

// Add edges to the graph.


addEdgeMatrix(adjMatrix, 0, 1);
addEdgeMatrix(adjMatrix, 0, 4);
addEdgeMatrix(adjMatrix, 1, 2);
addEdgeMatrix(adjMatrix, 1, 3);
addEdgeMatrix(adjMatrix, 1, 4);
addEdgeMatrix(adjMatrix, 2, 3);
addEdgeMatrix(adjMatrix, 3, 4);
// Display the constructed adjacency matrix.
printMatrix(adjMatrix);
return 0;
}
*/

● Pros:
○Fast Edge Operations: Checking if an edge exists between i and j, adding an
edge, or removing an edge (by setting the value to 0/INF) takes constant O(1)
time.9
○ Simplicity for Dense Graphs: Conceptually straightforward, especially when
the graph has many edges (dense graph, where E is close to V^2).3
○ Hardware Acceleration: Matrix operations can potentially be accelerated on
hardware like GPUs.10
● Cons:
○ Space Inefficiency: Requires O(V^2) space, regardless of the number of
edges. This is highly inefficient for sparse graphs (where E << V^2), which are
common in practice.3
○ Slow Neighbor Iteration: Finding all neighbors of a vertex requires iterating
through an entire row (or column), taking O(V) time.20 This makes traversal
algorithms like BFS and DFS inefficient (O(V^2) overall).20
○ Slow Node Addition/Deletion: Adding or removing a vertex requires resizing
and potentially copying the entire matrix, an O(V^2) operation.20

2. Adjacency List:
● Definition: An adjacency list represents a graph as an array (or vector) of lists (or
vectors, sets). The element at index i in the array, adjList[i], contains a list of all
vertices adjacent to vertex i.3 For weighted graphs, the list stores pairs of
{neighbor, weight}.16
● C++ Implementation: Typically implemented using std::vector<std::vector<int>>
for unweighted graphs or std::vector<std::vector<std::pair<int, int>>> for
weighted graphs. Adding an edge (u, v) with weight w involves
adjList[u].push_back({v, w}); (and adjList[v].push_back({u, w}); if undirected).12
While std::list can also be used (vector<list<pair<int, int>>>), vector often provides
better cache performance in C++ due to contiguous memory allocation for
elements within each inner vector, even though insertions/deletions in the middle
are slower than lists.38 Some competitive programming contexts use C-style
arrays of vectors (vector<int> adj[V];), but vector<vector<int>> is generally
preferred in modern C++ for safety and flexibility.29

#include <vector>
#include <list>
#include <utility>
#include <iostream>

using namespace std;

// Type definition for an adjacency list representing a weighted


undirected graph.
using AdjacencyList = vector<vector<pair<int, int>>>;

// Function to add an edge to the adjacency list.


// Parameters:
// - adjList: Reference to the adjacency list.
// - u: The starting vertex of the edge.
// - v: The ending vertex of the edge.
// - weight: The weight of the edge.
void addEdgeList(AdjacencyList& adjList, int u, int v, int weight) {
// Ensure vertices are within valid bounds.
if (u >= 0 && u < adjList.size() && v >= 0 && v < adjList.size())
{
adjList[u].push_back({v, weight});
adjList[v].push_back({u, weight}); // For undirected graphs,
add the reverse edge.
}
}

// Function to print the contents of the adjacency list.


// Parameters:
// - adjList: Constant reference to the adjacency list to be printed.
void printList(const AdjacencyList& adjList) {
cout << "Adjacency List:" << endl;
for (int i = 0; i < adjList.size(); ++i) {
cout << "Vertex " << i << ":";
for (const auto& edge : adjList[i]) {
cout << " -> (" << edge.first << ", weight " <<
edge.second << ")";
}
cout << endl;
}
}

/* Example Usage:
int main() {
int V = 5; // Number of vertices in the graph.
AdjacencyList adjList(V); // Initialize the adjacency list with V
vertices.

// Add edges to the graph.


addEdgeList(adjList, 0, 1, 10);
addEdgeList(adjList, 0, 4, 20);
addEdgeList(adjList, 1, 2, 30);
addEdgeList(adjList, 1, 3, 40);
addEdgeList(adjList, 1, 4, 50);
addEdgeList(adjList, 2, 3, 60);
addEdgeList(adjList, 3, 4, 70);

// Print the constructed adjacency list.


printList(adjList);
return 0;
}
*/

● Pros:
○ Space Efficiency: Space complexity is O(V + E), which is much better than
O(V^2) for sparse graphs.3
○ Efficient Neighbor Iteration: Iterating through all neighbors of a vertex u
takes O(degree(u)) time, which is efficient for traversal algorithms.20 Total
time for iterating all neighbors across all vertices is O(V+E).
○ Efficient Edge/Node Addition: Adding an edge is typically O(1) (amortized
for vector).20 Adding a node is also efficient.20
● Cons:
○ Slower Edge Checking: Checking if a specific edge (u, v) exists requires
searching u's adjacency list, taking O(degree(u)) time in the worst case.20
○ Slower Edge Removal: Removing an edge (u, v) requires finding v in u's list
(and u in v's list if undirected), which takes O(degree(u)) or O(degree(v))
time.21

3. Edge List:
● Definition: A simple list or array containing tuples or objects representing each
edge, often as (u, v, weight).4
● Complexity: Space complexity is O(E).3
● Use Cases: Useful when the primary task is to iterate over all edges (e.g.,
Kruskal's algorithm) or for simple graph input formats. Less efficient for
algorithms requiring frequent neighbor lookups (like BFS/DFS).9

C. Representation Choice Insight


Choosing between an adjacency matrix and an adjacency list is a critical first step in
solving graph problems, especially in an interview setting. The decision hinges on
understanding the trade-offs in the context of the specific problem's constraints and
requirements.

The key factors are the graph's density and the dominant operations needed.
● Density: If the graph is sparse (number of edges E is much smaller than the
maximum possible, V^2, often closer to O(V)), the O(V^2) space complexity of an
adjacency matrix becomes prohibitive. Adjacency lists, requiring only O(V + E)
space, are far more memory-efficient.3 Conversely, for dense graphs (E
approaches V^2), the O(V^2) space of the matrix is comparable to the O(V + E) ≈
O(V^2) space of the list, making space less of a deciding factor.10
● Operations: If the algorithm primarily involves iterating over neighbors of
nodes (like BFS, DFS, Dijkstra's, Prim's), adjacency lists are superior. Finding
neighbors takes O(degree) time per node, leading to efficient O(V+E) overall
traversal times.20 Adjacency matrices require O(V) time to find neighbors,
resulting in slower O(V^2) traversals.20 However, if the main operation is
checking for the existence of a specific edge (u, v) or quickly
adding/removing edges, the O(1) performance of an adjacency matrix is
advantageous compared to the O(degree(u)) lookup time for an adjacency list.9

Interview Context: For most graph problems encountered in interviews (traversals,


shortest paths on potentially sparse graphs, MSTs), the adjacency list is the preferred
representation due to its efficiency in neighbor iteration and better space complexity
for sparse graphs.11 Be prepared to justify this choice based on the expected sparsity
and the algorithm's operational needs. However, knowing the trade-offs and when a
matrix might be better demonstrates a deeper understanding.

D. Table: Graph Representation Comparison

Feature Adjacency Matrix Adjacency List

Space Complexity O(V^2) O(V + E)

Add Edge O(1) O(1) amortized

Remove Edge O(1) O(degree)

Check Edge (u,v) O(1) O(degree(u))

Iterate Neighbors O(V) O(degree)

Add/Remove Node O(V^2) Generally efficient (depends


on impl.)

Best For Dense graphs, Frequent edge Sparse graphs, Frequent


checks neighbor traversals

II. Graph Traversal Algorithms


Graph traversal involves systematically visiting all the nodes and edges of a graph.
The two fundamental traversal algorithms are Breadth-First Search (BFS) and Depth-
First Search (DFS).

A. Breadth-First Search (BFS)


● Concept: BFS explores the graph level by level or layer by layer.27 Starting
from a source node s, it first visits all nodes at distance 1 from s, then all nodes at
distance 2, and so on. This "breadth-wise" exploration ensures that nodes closer
to the source are visited before nodes farther away.43
● Mechanism: BFS uses a queue (First-In, First-Out data structure) to manage the
order of nodes to visit.2 It also requires a way to keep track of visited nodes,
typically using a boolean array or set, to avoid processing nodes multiple times
and getting trapped in cycles.27
● Algorithm Steps:
1. Initialize an empty queue Q and a visited array/set (e.g., vector<bool>
visited(V, false)), marking all nodes as unvisited.
2. Choose a starting node s. Mark s as visited (visited[s] = true) and enqueue it
into Q.27
3. While the queue Q is not empty: a. Dequeue a node u from the front of Q.27 b.
Process node u (e.g., add it to the result list, check if it's the target). c. Iterate
through all neighbors v of u (using the adjacency list adj[u]). d. For each
neighbor v: If v has not been visited (!visited[v]): i. Mark v as visited (visited[v]
= true). ii. Enqueue v into Q.27
4. If the graph might be disconnected, repeat steps 2-3 starting from any
unvisited node until all nodes are visited.45
● C++ Implementation (Adjacency List):

#include <vector>
#include <queue>
#include <iostream>

using namespace std;

// Function implementing Breadth-First Search (BFS) for a connected


component starting from a source node.
void bfsComponent(int source, int vertices, const vector<vector<int>>&
adjacencyList, vector<bool>& visitedNodes, vector<int>& bfsResult) {
queue<int> nodeQueue;

// Begin BFS traversal from the source node.


visitedNodes[source] = true;
nodeQueue.push(source);
while (!nodeQueue.empty()) {
int currentNode = nodeQueue.front();
nodeQueue.pop();
bfsResult.push_back(currentNode); // Process currentNode
(append to result vector).

// Explore adjacent nodes.


for (int adjacentNode : adjacencyList[currentNode]) {
if (!visitedNodes[adjacentNode]) {
visitedNodes[adjacentNode] = true;
nodeQueue.push(adjacentNode);
}
}
}
}

// Main function to perform BFS traversal on a graph, handling


potentially disconnected components.
vector<int> breadthFirstSearchOfGraph(int vertices, const
vector<vector<int>>& adjacencyList) {
vector<bool> visitedNodes(vertices, false);
vector<int> bfsResult;

// Iterate through all vertices to ensure traversal of


disconnected components.
for (int i = 0; i < vertices; ++i) {
if (!visitedNodes[i]) {
bfsComponent(i, vertices, adjacencyList, visitedNodes,
bfsResult);
}
}
return bfsResult;
}

/* Example demonstrating the usage of the BFS function with an


adjacency list representation of a graph.
int main() {
int vertices = 5;
vector<vector<int>> adjacencyList(vertices);
// Define unweighted edges for BFS example.
adjacencyList.push_back(1); adjacencyList.push_back(0);
adjacencyList.push_back(4); adjacencyList.push_back(0);
adjacencyList.push_back(2); adjacencyList.push_back(1);
adjacencyList.push_back(3); adjacencyList.push_back(1);
adjacencyList.push_back(4); adjacencyList.push_back(1);
adjacencyList.push_back(3); adjacencyList.push_back(2);
adjacencyList.push_back(4); adjacencyList.push_back(3);

vector<int> result = breadthFirstSearchOfGraph(vertices,


adjacencyList);

cout << "Breadth-First Search Traversal: ";


for (int node : result) {
cout << node << " ";
}
cout << endl; // Output may vary based on the order of neighbors:
0 1 4 2 3.

return 0;
}
*/

● Complexity Analysis:
○ Time: O(V + E). Each vertex is enqueued and dequeued exactly once (O(V)).
Each edge (u, v) is examined exactly twice in an undirected graph (once from
u, once from v) or once in a directed graph when iterating through neighbors
(O(E)). Thus, the total time is proportional to V + E.3 If using an adjacency
matrix, finding neighbors takes O(V) for each node, leading to O(V^2) time
complexity.27
○ Space: O(V). The space is required for the visited array (O(V)) and the queue.
In the worst case (e.g., a star graph), the queue might hold up to O(V)
nodes.27
● Applications:
○ Shortest Path in Unweighted Graphs: BFS inherently finds the shortest
path in terms of the number of edges from the source node to all other
reachable nodes.3 This is because it explores level by level, guaranteeing that
the first time a node is reached, it is via a path with the minimum possible
number of edges.
○ Level Order Traversal: Directly performs level order traversal of trees or
graphs.36
○ Connectivity: Finding connected components in undirected graphs.3
Running BFS from an unvisited node finds all nodes in its component.
○ Cycle Detection (Undirected): Can detect cycles in undirected graphs by
checking if a visited node (that is not the immediate parent) is encountered.40
○ Bipartite Graph Check: Can be used to check if a graph is bipartite by
attempting a 2-coloring during traversal.51
○ Other: Network broadcasting, web crawling, finding neighbor nodes in P2P
networks, GPS navigation (finding nearby locations).27
Practice Problems:

A list of problems, along with their associated frequency of appearance:

● Flood Fill (74)


● 01 Matrix (72)
● Shortest Distance from All Buildings (72)
● Rotting Oranges (71)
● Pacific Atlantic Water Flow
● Surrounded Regions
● Shortest Path in Binary Matrix
● Number of Islands (48)
● Clone Graph (51)
● Word Ladder (51)
● Number of Connected Components in an Undirected Graph (62)
● All Nodes Distance K in Binary Tree
● Graph Valid Tree
● Trapping Rain Water II (Can use BFS on states)

B. Depth-First Search (DFS)


● Concept: DFS explores a graph by going as deep as possible along a path
before backtracking.3 When it hits a dead end (a node with no unvisited
neighbors) or completes exploring a branch, it moves back up the path to find an
unexplored branch and dives down again.28
● Mechanism: DFS naturally lends itself to a recursive implementation, where the
function call stack implicitly manages the backtracking.4 An iterative version can
be implemented using an explicit stack (Last-In, First-Out).4 Like BFS, it requires
a visited array/set to prevent infinite loops in cyclic graphs and redundant work.28
For specific tasks like cycle detection, additional state tracking (like colors or
parent pointers) is often used.65
● Algorithm Steps:
○ Recursive:
1. Initialize a visited array/set to all false.
2. Define a recursive function dfs(u): a. Mark node u as visited (visited[u] =
true). b. Process node u (e.g., add to result, perform checks). c. For each
neighbor v of u: If v is not visited (!visited[v]): Call dfs(v).
3. Iterate through all vertices i from 0 to V-1. If i is not visited, call dfs(i) to
handle disconnected components.37
○ Iterative (Stack-based):
1. Initialize an empty stack S and a visited array/set to all false.
2. Iterate through all vertices i from 0 to V-1. If i is not visited: a. Push i onto
the stack S. b. While the stack S is not empty: i. Pop a node u from S. ii. If
u is not visited: Mark u as visited (visited[u] = true). Process node u. Push
all neighbors v of u onto the stack S.75 (Note: To closely mimic recursive
DFS order, neighbors are often pushed in reverse order of how they
appear in the adjacency list 75).
● C++ Implementation (Adjacency List):

#include <vector>
#include <stack>
#include <iostream>
#include <algorithm> // For reverse

using namespace std;

// Recursive Depth-First Search (DFS) Helper Function


void dfs_recursive_helper(int node, const vector<vector<int>>&
adjacencyList, vector<bool>& visitedNodes, vector<int>& dfsResult) {
visitedNodes[node] = true;
dfsResult.push_back(node); // Process the current node
for (int neighbor : adjacencyList[node]) {
if (!visitedNodes[neighbor]) {
dfs_recursive_helper(neighbor, adjacencyList,
visitedNodes, dfsResult);
}
}
}

// Recursive Depth-First Search (DFS) Main Function (Handles


Disconnected Graphs)
vector<int> dfsRecursive(int numberOfVertices, const
vector<vector<int>>& adjacencyList) {
vector<bool> visitedNodes(numberOfVertices, false);
vector<int> dfsResult;
for (int i = 0; i < numberOfVertices; ++i) {
if (!visitedNodes[i]) {
dfs_recursive_helper(i, adjacencyList, visitedNodes,
dfsResult);
}
}
return dfsResult;
}

// Iterative Depth-First Search (DFS) Main Function (Handles


Disconnected Graphs)
vector<int> dfsIterative(int numberOfVertices, const
vector<vector<int>>& adjacencyList) {
vector<bool> visitedNodes(numberOfVertices, false);
vector<int> dfsResult;
stack<int> nodeStack;

for (int i = 0; i < numberOfVertices; ++i) {


if (!visitedNodes[i]) {
nodeStack.push(i); // Start DFS from an unvisited node
while (!nodeStack.empty()) {
int currentNode = nodeStack.top();
nodeStack.pop();
// Check if the node has been visited (necessary for
iterative with explicit stack)
if (!visitedNodes[currentNode]) {
visitedNodes[currentNode] = true;
dfsResult.push_back(currentNode); // Process the
current node

// Push neighbors onto the stack in reverse order


to mimic recursion stack behavior
vector<int> neighbors =
adjacencyList[currentNode];
reverse(neighbors.begin(), neighbors.end());
for (int neighbor : neighbors) {
if (!visitedNodes[neighbor]) { //
Optimization: only push unvisited neighbors
nodeStack.push(neighbor);
}
}
}
}
}
}
return dfsResult;
}

/* Example Usage (with an adjacency list representing a graph):


int main() {
int numberOfVertices = 5;
vector<vector<int>> adjacencyList(numberOfVertices);
// Definition of unweighted edges for the graph example
adjacencyList.push_back(1); adjacencyList.push_back(0);
adjacencyList.push_back(4); adjacencyList.push_back(0);
adjacencyList.push_back(2); adjacencyList.push_back(1);
adjacencyList.push_back(3); adjacencyList.push_back(1);
adjacencyList.push_back(4); adjacencyList.push_back(1);
adjacencyList.push_back(3); adjacencyList.push_back(2);
adjacencyList.push_back(4); adjacencyList.push_back(3);

vector<int> recursiveResult = dfsRecursive(numberOfVertices,


adjacencyList);
cout << "Recursive DFS: ";
for (int node : recursiveResult) {
cout << node << " ";
}
cout << endl; // Output order depends on the start node & neighbor
order, e.g., 0 1 2 3 4

vector<int> iterativeResult = dfsIterative(numberOfVertices,


adjacencyList);
cout << "Iterative DFS: ";
for (int node : iterativeResult) {
cout << node << " ";
}
cout << endl; // Output order depends on the start node & neighbor
order, e.g., 0 4 3 2 1 (if neighbors pushed reversed)

return 0;
}
*/

● Complexity Analysis:
○ Time: O(V + E). Similar to BFS, each vertex is visited once, and each edge is
considered once (directed) or twice (undirected).3 If using an adjacency
matrix, it becomes O(V^2).28
○ Space: O(V). Space is needed for the visited array. Additionally, space is
required for the call stack in the recursive version or the explicit stack in the
iterative version. In the worst case (e.g., a long path graph), the stack depth
can reach O(V).28
● Applications:
○ Cycle Detection: Very effective for detecting cycles in both directed (using
colors/states) and undirected graphs (using parent tracking).3
○ Topological Sorting: The reverse order of finishing times in a DFS traversal
of a DAG yields a topological sort.3
○ Connectivity: Finding connected components (undirected) and strongly
connected components (directed - Kosaraju's, Tarjan's algorithms are DFS-
based).3
○ Pathfinding & Maze Solving: Exploring paths, though not guaranteed to find
the shortest path in general graphs.28
○ Backtracking: The recursive nature is ideal for problems requiring exhaustive
search and backtracking.28 Examples include solving puzzles like Sudoku or N-
Queens (though often modeled implicitly as state graphs).

Practice Problems :

1. Number of Islands
2. Number of Provinces
3. Max Area of Island
4. Surrounded Regions
5. Pacific Atlantic Water Flow
6. Clone Graph
7. Longest Increasing Path in a Matrix
8. Word Search
9. Word Search II
10. Number of Connected Components in an Undirected Graph
11. Graph Valid Tree
12. Course Schedule (Cycle Detection)
13. Course Schedule II (Topological Sort)
14. Find Eventual Safe States (Related to Cycle Detection)
15. Minimum Height Trees (Utilizing Breadth-First Search/Depth-First Search on
Tree-like Structures)

III. Shortest Path Algorithms


Finding the shortest path between nodes is a classic graph problem with numerous
applications, from GPS navigation to network routing.27 The choice of algorithm
depends heavily on the properties of the graph's edge weights.

A. Introduction
● Problem Definition: Given a weighted graph G = (V, E), find a path between two
vertices (or from a single source to all other vertices, or between all pairs of
vertices) such that the sum of the weights of the edges in the path is minimized.57
● Variations:
○ Single-Source Shortest Path (SSSP): Find shortest paths from a designated
source vertex s to all other vertices.51 Dijkstra and Bellman-Ford solve this.
BFS solves the unweighted version.
○ All-Pairs Shortest Path (APSP): Find the shortest path between every pair
of vertices in the graph.17 Floyd-Warshall solves this. Alternatively, run an
SSSP algorithm from each vertex.
● Edge Weight Significance:
○ Unweighted: All edge weights are 1. BFS is the most efficient algorithm.27
○ Non-Negative Weights: Edge weights are >= 0. Dijkstra's algorithm is
typically the most efficient.3
○ Negative Weights Allowed (No Negative Cycles): Edge weights can be
negative, but no cycle exists where the sum of edge weights is negative.
Bellman-Ford works; Dijkstra does not.51 Floyd-Warshall also works for
APSP.114
○ Negative Cycles: If a negative cycle is reachable from the source, the
shortest path is undefined (can be made arbitrarily small by traversing the
cycle). Bellman-Ford and Floyd-Warshall can detect negative cycles.51

B. Dijkstra's Algorithm
● Concept: A greedy algorithm that finds the shortest paths from a single source
vertex s to all other vertices in a weighted graph where all edge weights are non-
negative.3 It maintains a set of visited vertices for which the shortest path is
known and iteratively adds the "closest" unvisited vertex to this set.
● Mechanism:
1. Initialize distances: dist[s] = 0, and dist[v] = infinity for all other vertices v.
2. Maintain a set (or priority queue) Q of vertices not yet finalized. Initially, Q
contains all vertices.
3. While Q is not empty: a. Select the vertex u in Q with the minimum dist[u]
value. b. Remove u from Q (mark as finalized/visited). c. For each neighbor v
of u: Perform relaxation. If dist[u] + weight(u, v) < dist[v], update dist[v] =
dist[u] + weight(u, v).4 If using a priority queue, add/update v with its new
distance.
● Why Non-Negative Weights are Crucial: Dijkstra's algorithm relies on the
greedy choice: once a vertex u is extracted as the minimum distance vertex from
Q, its dist[u] is considered the final shortest path distance. This holds true only if
edge weights are non-negative. If a negative edge existed elsewhere, a path
going through that edge might later reveal a shorter path to u after u has already
been finalized, violating the algorithm's core assumption.51
● Data Structure Choice: A min-priority queue is the standard data structure for
efficiently implementing step 3a (extracting the minimum distance vertex).3 C++'s
std::priority_queue doesn't directly support the "decrease-key" operation often
mentioned in theoretical descriptions. The common workaround is to simply
insert the vertex with its new, smaller distance into the priority queue, allowing
duplicates. When extracting elements, check if the extracted distance matches
the current best known distance; if not, it's a stale entry and should be ignored.32
std::set<pair<int, int>> can also be used, offering logarithmic time for finding the
minimum, removing, and inserting, effectively simulating decrease-key.32
priority_queue often has better constant factors.32
● C++ Implementation (Priority Queue):

#include <vector>
#include <queue>
#include <utility> // For std::pair
#include <limits> // For numeric_limits

using namespace std;

const int INFINITY = numeric_limits<int>::max();


// Utilize pair<int, int> for {weight, vertex} to capitalize on
default min-heap behavior on the first element
using IntegerPair = pair<int, int>;

vector<int> calculateShortestPaths(int numberOfVertices, const


vector<vector<pair<int, int>>>& adjacencyList, int sourceVertex) {
// Minimum-priority queue to maintain {distance, vertex} pairs
priority_queue<IntegerPair, vector<IntegerPair>,
greater<IntegerPair>> priorityQueue;

// Distance vector, initialized to infinity


vector<int> distance(numberOfVertices, INFINITY);

// Enqueue the source vertex and set its distance to zero


priorityQueue.push({0, sourceVertex});
distance[sourceVertex] = 0;

while (!priorityQueue.empty()) {
// Extract the vertex with the minimal distance value
int currentDistance = priorityQueue.top().first;
int currentVertex = priorityQueue.top().second;
priorityQueue.pop();
// Optimization: If the extracted entry is outdated, proceed
to the next entry
if (currentDistance > distance[currentVertex]) {
continue;
}

// Iterate over the adjacent vertices of the current vertex


for (const auto& edge : adjacencyList[currentVertex]) {
int adjacentVertex = edge.first;
int edgeWeight = edge.second;

// Check for a shorter path to the adjacent vertex via the


current vertex
if (distance[currentVertex] != INFINITY &&
distance[adjacentVertex] > distance[currentVertex] + edgeWeight) {
// Update the distance of the adjacent vertex
distance[adjacentVertex] = distance[currentVertex] +
edgeWeight;
// Enqueue the updated distance into the priority
queue
priorityQueue.push({distance[adjacentVertex],
adjacentVertex});
}
}
}
return distance;
}

/* Example Usage:
int main() {
int numberOfVertices = 5;
vector<vector<pair<int, int>>> adjacencyList(numberOfVertices);
// Populate the adjacency list with edges using
addEdgeList(adjacencyList, u, v, weight);
// Note: Dijkstra's algorithm requires only one direction in the
adjacency list for directed graphs
// Example graph (undirected, add both directions or adapt the
algorithm):
adjacencyList.push_back({1, 4}); adjacencyList.push_back({0, 4});
adjacencyList.push_back({2, 8}); adjacencyList.push_back({0, 8});
adjacencyList.push_back({4, 6}); adjacencyList.push_back({1, 6});
adjacencyList.push_back({3, 2}); adjacencyList.push_back({2, 2});
adjacencyList.push_back({4, 10}); adjacencyList.push_back({3,
10});

int sourceVertex = 0;
vector<int> shortestDistances =
calculateShortestPaths(numberOfVertices, adjacencyList, sourceVertex);

cout << "Vertex Distance from Source " << sourceVertex << endl;
for (int i = 0; i < numberOfVertices; ++i)
cout << i << "\t\t" << (shortestDistances[i] == INFINITY ?
"INF" : to_string(shortestDistances[i])) << endl;
// Expected Output (for source 0): 0: 0, 1: 4, 2: 8, 3: 10, 4: 10

return 0;
}
*/

● Complexity Analysis:
○ Time: O(E log V) or O((V + E) log V) using a binary heap (priority queue). Each
vertex is added/extracted once (O(V log V)). Each edge relaxation might lead
to adding a new element to the priority queue (O(E log V)).3
○ Space: O(V + E) for storing the graph (adjacency list), the distance array, and
the priority queue (which can hold up to O(E) elements in the duplicate-entry
implementation, but O(E) <= O(V^2), and log E is O(log V)).109
● Practice Problems:
1. Network Delay Time
2. Path With Minimum Effort
3. Minimum Obstacle Removal to Reach Corner
4. Number of Ways to Arrive at Destination (Path Tracking Required)
5. Minimum Time to Visit a Cell In a Grid
6. Shortest Path in Binary Matrix (Consider Dijkstra's Algorithm for Non-Uniform
Weights)
7. Find the Safest Path in a Grid (Involves Binary Search and Graph Traversal
Algorithms)
Supplementary Material: LeetCode 1514. Path with Maximum Probability (Utilize a modified
Dijkstra's Algorithm for Probability Optimization).

C. Bellman-Ford Algorithm
● Concept: A more general SSSP algorithm that can handle negative edge
weights, unlike Dijkstra's.51 It is also capable of detecting negative cycles
reachable from the source.
● Mechanism: The core idea is based on the principle of relaxation. It repeatedly
relaxes all edges in the graph. If a graph with V vertices has no negative cycles,
the shortest path from the source to any other vertex can have at most V-1
edges.115 Bellman-Ford leverages this by performing V-1 passes of relaxing every
edge in the graph.51
1. Initialize distances: dist[s] = 0, dist[v] = infinity for all other v.
2. Repeat V-1 times: For each edge (u, v) with weight w: Relax the edge: if
dist[u] + w < dist[v], then update dist[v] = dist[u] + w.
3. Negative Cycle Detection: After V-1 passes, perform one additional pass
through all edges. If any distance dist[v] can still be improved (i.e., dist[u] + w
< dist[v] for some edge (u, v)), then a negative cycle reachable from the
source exists.51 In such cases, shortest paths are ill-defined (can be infinitely
small).
● Why V-1 Relaxations Suffice (No Negative Cycles): Any simple shortest path
(without cycles) contains at most V-1 edges. In the first pass, Bellman-Ford finds
shortest paths using at most 1 edge. In the second pass, it finds shortest paths
using at most 2 edges (by potentially extending the 1-edge paths found in pass
1), and so on. After k passes, the algorithm guarantees finding the shortest paths
that use at most k edges.115 Therefore, after V-1 passes, it must have found the
shortest simple paths.115 If a distance can be further reduced in the V-th pass, it
implies the shortest path requires V or more edges, which is only possible if it
involves traversing a negative cycle.113
● C++ Implementation (Edge List): Bellman-Ford is often implemented using a
simple list of edges, as it needs to iterate through all edges repeatedly.

#include <vector>
#include <limits>
#include <iostream>

using std::vector;
using std::cout;
using std::endl;
using std::numeric_limits;
using std::string;

const long long INFINITY_VALUE = numeric_limits<long long>::max();

struct Edge {
int sourceVertex;
int destinationVertex;
int weight;
};

// Determines whether a negative cycle exists in the graph.


// If no negative cycle is present, calculates shortest distances from
a source vertex.
// Returns true if a negative cycle is found, false otherwise.
bool detectNegativeCycleAndCalculateShortestDistances(int
numberOfVertices, const vector<Edge>& edges, int sourceVertex,
vector<long long>& shortestDistances) {
shortestDistances.assign(numberOfVertices, INFINITY_VALUE);
shortestDistances[sourceVertex] = 0;

// Relax edges V-1 times to calculate shortest paths.


for (int i = 1; i <= numberOfVertices - 1; ++i) {
for (const Edge& edge : edges) {
int u = edge.sourceVertex;
int v = edge.destinationVertex;
int weight = edge.weight;
if (shortestDistances[u] != INFINITY_VALUE &&
shortestDistances[v] > shortestDistances[u] + weight) {
shortestDistances[v] = shortestDistances[u] + weight;
}
}
}

// Check for negative cycles by performing one additional


relaxation.
for (const Edge& edge : edges) {
int u = edge.sourceVertex;
int v = edge.destinationVertex;
int weight = edge.weight;
if (shortestDistances[u] != INFINITY_VALUE &&
shortestDistances[v] > shortestDistances[u] + weight) {
// Negative cycle detected, invalidate path distances.
std::fill(shortestDistances.begin(),
shortestDistances.end(), -INFINITY_VALUE);
return true;
}
}

return false; // No negative cycle detected.


}

/* Example Usage:
int main() {
int numberOfVertices = 5;
vector<Edge> edges = {
{0, 1, -1}, {0, 2, 4}, {1, 2, 3},
{1, 3, 2}, {1, 4, 2}, {3, 2, 5},
{3, 1, 1}, {4, 3, -3}
// Example with a negative cycle: {0,1,1}, {1,2,-1}, {2,0,-1}
};
int source = 0;
vector<long long> shortestDistances;

bool hasNegativeCycle =
detectNegativeCycleAndCalculateShortestDistances(numberOfVertices,
edges, source, shortestDistances);

if (hasNegativeCycle) {
cout << "Graph contains a negative cycle reachable from source
" << source << endl;
} else {
cout << "Vertex Distance from Source " << source << endl;
for (int i = 0; i < numberOfVertices; ++i) {
cout << i << "\t\t"
<< (shortestDistances[i] == INFINITY_VALUE ? "INF" :
(shortestDistances[i] == -INFINITY_VALUE ? "-INF"
: std::to_string(shortestDistances[i])))
<< endl;
}
// Expected Output (for source 0, no neg cycle example):
// 0: 0, 1: -1, 2: 2, 3: -2, 4: 1
}

return 0;
}
*/

● Complexity Analysis:
○ Time: O(V * E). The algorithm consists of V passes, and each pass iterates
through all E edges.60
○ Space: O(V) to store the distances. O(E) if storing edges explicitly.114
● Practice Problems:
● Cheapest Flights Within K Stops (Can be adapted from Bellman-Ford by
limiting passes to K) 72
● Supplement: Problems explicitly involving negative edge weights or requiring
negative cycle detection (e.g., arbitrage detection). CSES Problem Set:
Shortest Routes II (requires negative cycle check).

D. Floyd-Warshall Algorithm
● Concept: An algorithm for finding the shortest paths between all pairs of
vertices (APSP) in a weighted graph.17 It uses dynamic programming.114 It can
handle negative edge weights, but like Bellman-Ford, it assumes there are no
negative cycles.114
● Mechanism: It works by iteratively considering each vertex k as a potential
intermediate vertex on the shortest path between any two vertices i and j. It
updates the distance dist[i][j] if the path from i to j through k (dist[i][k] + dist[k]
[j]) is shorter than the current known shortest path dist[i][j].17
1. Initialize a distance matrix dist[V][V]. dist[i][j] is the weight of the direct edge
(i, j) if it exists, 0 if i == j, and infinity otherwise.
2. Use three nested loops: for k from 0 to V-1, for i from 0 to V-1, for j from 0 to
V-1.
3. Inside the innermost loop, apply the update rule: dist[i][j] = min(dist[i][j],
dist[i][k] + dist[k][j]).17
4. After the loops complete, dist[i][j] holds the shortest path distance from i to j.
● Why k Must Be the Outer Loop: The order k, i, j is essential. When the outer
loop is at iteration k, the algorithm computes the shortest paths between all pairs
(i, j) considering only intermediate vertices from the set {0, 1,..., k}. For this
computation to be correct, the values dist[i][k] and dist[k][j] must represent the
shortest paths using only intermediate vertices from {0, 1,..., k-1}, which are
guaranteed to have been computed in the previous iterations of the outer k loop.
If k were an inner loop, this subproblem optimality wouldn't hold.120
● Negative Cycle Detection: After the algorithm runs, if any diagonal element
dist[i][i] is negative, it indicates that vertex i is part of or can reach a negative
cycle.120
● C++ Implementation:

#include <vector>
#include <algorithm> // For std::min
#include <limits> // For numeric_limits
#include <iostream>

using namespace std;

const int INFINITY_VALUE = 1e9; // Represents infinity for Floyd-


Warshall algorithm

/**
* Implements the Floyd-Warshall algorithm to find the shortest paths
between all pairs of vertices in a graph.
*
* @param numVertices The number of vertices in the graph.
* @param distanceMatrix A 2D vector representing the initial distance
matrix, where:
* - distanceMatrix[i][j] = weight(i, j) if an
edge exists between vertices i and j.
* - distanceMatrix[i][i] = 0.
* - distanceMatrix[i][j] = INFINITY_VALUE if no
direct edge exists between vertices i and j.
*/
void floydWarshall(int numVertices, vector<vector<int>>&
distanceMatrix) {
for (int k = 0; k < numVertices; ++k) {
for (int i = 0; i < numVertices; ++i) {
for (int j = 0; j < numVertices; ++j) {
if (distanceMatrix[i][k] != INFINITY_VALUE &&
distanceMatrix[k][j] != INFINITY_VALUE &&
distanceMatrix[i][j] > distanceMatrix[i][k] +
distanceMatrix[k][j]) {
distanceMatrix[i][j] = distanceMatrix[i][k] +
distanceMatrix[k][j];
}
}
}
}

// Optional: Detection of negative cycles


// for (int i = 0; i < numVertices; ++i) {
// if (distanceMatrix[i][i] < 0) {
// cout << "Negative cycle detected involving vertex " <<
i << endl;
// // Handle negative cycle case (e.g., set paths
involving it to negative infinity)
// return;
// }
// }
}

/* Example Demonstration:
int main() {
int numVertices = 4;
// Initialization of distance matrix based on direct edges
vector<vector<int>> distanceMatrix = {
{0, 5, INFINITY_VALUE, 10},
{INFINITY_VALUE, 0, 3, INFINITY_VALUE},
{INFINITY_VALUE, INFINITY_VALUE, 0, 1},
{INFINITY_VALUE, INFINITY_VALUE, INFINITY_VALUE, 0}
};
floydWarshall(numVertices, distanceMatrix);

cout << "All-Pairs Shortest Paths Matrix:" << endl;


for (int i = 0; i < numVertices; ++i) {
for (int j = 0; j < numVertices; ++j) {
if (distanceMatrix[i][j] == INFINITY_VALUE)
cout << "INF ";
else
cout << distanceMatrix[i][j] << " ";
}
cout << endl;
}
// Expected Result:
// 0 5 8 9
// INF 0 3 4
// INF INF 0 1
// INF INF INF 0

return 0;
}
*/

● Complexity Analysis:
○ Time: O(V^3). The three nested loops iterating up to V dominate the
runtime.114
○ Space: O(V^2) to store the distance matrix.114
● Practice Problems:
● Find the City With the Smallest Number of Neighbors at a Threshold Distance 72
● Supplement: LeetCode 399. Evaluate Division (Can be solved via APSP).
Problems where APSP is needed and V is small enough (e.g., V <= ~400).

E. Table: Shortest Path Algorithm Comparison

Feature BFS Dijkstra Bellman-Ford Floyd-Warshall

Graph Type Unweighted Weighted (Non- Weighted Weighted


negative) (Negative OK) (Negative OK)
Handles Neg. No No Yes Yes
Weights

Detects Neg. No (Detects No Yes (Reachable Yes (Any


Cycles general cycles) from source) negative cycle)

Problem Type SSSP SSSP SSSP APSP

Time O(V + E) O(E log V) O(V * E) O(V^3)


Complexity (Priority Queue)

Space O(V) O(V + E) O(V) (+ O(E) for O(V^2)


Complexity edge list)

27

IV. Minimum Spanning Tree (MST) Algorithms


A. Introduction to MST
● Definition: Given a connected, undirected, edge-weighted graph, a Minimum
Spanning Tree (MST) is a subgraph that meets two criteria:
1. It is a spanning tree: It includes all vertices of the original graph and is a tree
(i.e., it is connected and contains no cycles).
2. It has the minimum possible total edge weight among all possible spanning
trees.139 For graphs that are not connected, we talk about a Minimum
Spanning Forest (MSF), which is the union of MSTs for each connected
component of the graph.142
● Key Properties:
○ Cut Property: For any cut (a partition of the graph's vertices into two disjoint
sets), if an edge e has the minimum weight among all edges crossing the cut,
then e must belong to some MST.142 This property is fundamental to the
correctness of greedy MST algorithms like Prim's and Kruskal's.
○ Cycle Property: For any cycle in the graph, the edge with the maximum
weight in that cycle cannot be part of any MST (unless it's needed to connect
components, which wouldn't happen if it's the heaviest in a cycle within a
component).142
○Uniqueness: If all edge weights in the graph are distinct, then the MST is
unique.142 If there are duplicate weights, multiple MSTs with the same
minimum total weight might exist.146
● Applications: MST algorithms are widely used in problems involving finding the
cheapest way to connect a set of points or nodes. Common applications include:
○ Network Design: Designing cost-effective computer networks,
telecommunication networks, transportation routes (roads, pipelines), water
supply systems, and electrical grids.140
○ Clustering: Algorithms like single-linkage clustering use MST concepts to
group similar data points.140 Removing the most expensive edges from an MST
can partition data into clusters.
○ Image Processing: Image segmentation and feature extraction.140
○ Approximation Algorithms: Used as a subroutine in algorithms for NP-hard
problems like the Traveling Salesman Problem (TSP) and the Steiner Tree
problem.140
○ Other: Circuit design, phylogenetic tree construction, handwriting
recognition.148

B. Prim's Algorithm
● Concept: A greedy algorithm that builds the MST incrementally, starting from an
arbitrary vertex.3 It maintains a set of vertices already included in the MST. In
each step, it adds the minimum-weight edge that connects a vertex inside the
current MST to a vertex outside the MST.140 This process continues until all
vertices are included.
● Mechanism:
1. Initialize: Create a set mstSet (or visited array) to track vertices in the MST,
initially empty. Create a key array to store the minimum edge weight
connecting each vertex v to the MST (key[v]), initialized to infinity for all v
except the start vertex s (key[s] = 0). Optionally, maintain a parent array to
reconstruct the MST edges.
2. Use a min-priority queue pq storing pairs {key[v], v}. Initialize pq with {0,
s}.140
3. While pq is not empty: a. Extract the vertex u with the minimum key from pq.
b. If u is already in mstSet (visited), continue (skip stale entries). c. Add u to
mstSet. Add the edge connecting u to its parent (if tracked) to the MST
result. d. For each neighbor v of u: If v is not in mstSet and the edge weight
weight(u, v) is less than key[v]: Update key[v] = weight(u, v). Update the
parent of v to u. Add {key[v], v} to pq (or perform decrease-key if the priority
queue supports it).
● C++ Implementation (Priority Queue):

#include <vector>
#include <queue>
#include <utility> // For std::pair
#include <limits> // For numeric_limits

using namespace std;

const int INF_PRIM = numeric_limits<int>::max();


// Use pair<int, int> for {weight, vertex}
using iPair = pair<int, int>;

// Function to determine the sum of edge weights comprising the


Minimum Spanning Tree.
// adj represents the adjacency list: vector<vector<pair<int, int>>>
adj(V); adj[u] = {{v1, w1}, {v2, w2},...}
int primMST(int V, const vector<vector<pair<int, int>>>& adj) {
// Min-priority queue to manage {key, vertex}
priority_queue<iPair, vector<iPair>, greater<iPair>> pq;

vector<int> key(V, INF_PRIM); // Stores the minimum edge weight


to connect a vertex to the MST
vector<int> parent(V, -1); // Records the parent in the MST
vector<bool> inMST(V, false); // Indicates vertices included in
the MST

// Initialization begins with the first vertex (vertex 0)


key = 0;
pq.push({0, 0}); // {key, vertex}

int mstWeightSum = 0;

while (!pq.empty()) {
// Extract vertex u possessing the minimum key value
int u = pq.top().second;
int u_key = pq.top().first; // Obtain the key associated with
u
pq.pop();

// If u is already within the MST or the extracted key is not


current, proceed to the next iteration
if (inMST[u] || u_key > key[u]) {
continue;
}

// Incorporate u into the MST


inMST[u] = true;
mstWeightSum += key[u]; // Augment the sum with the edge
weight connecting u to the MST

// Explore adjacent vertices of u


for (const auto& edge : adj[u]) {
int v = edge.first;
int weight = edge.second;

// If v is not in the MST and the weight of (u,v) is less


than the current key of v
if (!inMST[v] && weight < key[v]) {
// Revise the key of v
key[v] = weight;
pq.push({key[v], v});
parent[v] = u; // Update the parent for MST
reconstruction (optional)
}
}
}

// Optional: Validation of MST (all nodes must be included)


// for(int i=0; i<V; ++i) if(!inMST[i]) return -1; // Graph is not
connected

return mstWeightSum;
}

/* Example Usage:
int main() {
int V = 5;
vector<vector<pair<int, int>>> adj(V);
// Procedure to add undirected edges
auto addEdgePrim = [&](int u, int v, int w){
adj[u].push_back({v, w});
adj[v].push_back({u, w});
};
addEdgePrim(0, 1, 2);
addEdgePrim(0, 3, 6);
addEdgePrim(1, 2, 3);
addEdgePrim(1, 3, 8);
addEdgePrim(1, 4, 5);
addEdgePrim(2, 4, 7);
addEdgePrim(3, 4, 9);

int minCost = primMST(V, adj);


cout << "Minimum Spanning Tree Weight (Prim's): " << minCost <<
endl; // Result: 16 (Edges: (0,1,2), (1,2,3), (1,4,5), (0,3,6) ->
2+3+5+6=16. Let's verify Prim's algorithm: Start 0.
key={0,inf,inf,inf,inf}. pq={(0,0)}. Process (0,0). mst=0. inMST=T.
Neighbors: (1,2), (3,6). key={0,2,inf,6,inf}. pq={(2,1), (6,3)}.
Process (2,1). mst=0+2=2. inMST=T. Neighbors: (0,2)-skip, (2,3),
(3,8), (4,5). Update key=3, key=min(6,8)=6, key=5. pq={(3,2), (5,4),
(6,3)}. Process (3,2). mst=2+3=5. inMST=T. Neighbors: (1,3)-skip,
(4,7). Update key=min(5,7)=5. pq={(5,4), (6,3)}. Process (5,4).
mst=5+5=10. inMST=T. Neighbors: (1,5)-skip, (2,7)-skip, (3,9). Update
key=min(6,9)=6. pq={(6,3)}. Process (6,3). mst=10+6=16. inMST=T.
Neighbors: (0,6)-skip, (1,8)-skip, (4,9)-skip. pq empty. Total weight
= 16.

return 0;
}
*/

● Complexity Analysis:
○ Time: O(E log V) or O((V + E) log V) using a binary heap (priority queue).
Extracting the minimum V times takes O(V log V). Each edge might lead to a
decrease-key operation (or insertion in the common C++ implementation),
totaling O(E log V).3 The dominant term is usually O(E log V).
○ Space: O(V + E) for the adjacency list, priority queue, key array, and visited
array.158
● Practice Problems:
● Min Cost to Connect All Points 118
● Supplement: LeetCode 1135. Connecting Cities With Minimum Cost.

C. Kruskal's Algorithm
● Concept: Another greedy algorithm for finding the MST. It operates by
considering edges in increasing order of weight and adding an edge to the
growing MST (initially empty) if and only if adding the edge does not form a
cycle.3
● Mechanism:
1. Create a list of all edges (u, v, weight) in the graph.
2. Sort the edges in non-decreasing order of their weights.139
3. Initialize an empty set MST to store the edges of the minimum spanning tree.
4. Initialize a Union-Find (Disjoint Set Union - DSU) data structure with V
disjoint sets, one for each vertex.74
5. Iterate through the sorted edges (u, v, weight): a. Check if vertices u and v
are already in the same component using the DSU's find operation (find(u)!=
find(v)). b. If they are in different components (i.e., adding the edge does not
create a cycle): Add the edge (u, v, weight) to MST. Merge the components of
u and v using the DSU's union operation (union(u, v)).139
6. Stop when MST contains V-1 edges (or when all edges have been processed).
● Data Structures: Requires sorting the edges and an efficient Union-Find data
structure (with path compression and union by rank/size optimizations) for cycle
detection.74
● C++ Implementation:

#include <vector>
#include <numeric> // For std::iota
#include <algorithm> // For std::sort
#include <iostream>

using namespace std;

struct Edge {
int u, v, weight;
// Comparator for sorting edges by weight
bool operator<(const Edge& other) const {
return weight < other.weight;
}
};

// Disjoint Set Union (with Path Compression and Union by Rank)


struct DisjointSet {
vector<int> parent;
vector<int> rank;

DisjointSet(int n) {
parent.resize(n);
iota(parent.begin(), parent.end(), 0); // Initialize parent[i]
= i
rank.assign(n, 0); // Initialize rank of all nodes to 0
}

int find(int i) {
if (parent[i] == i)
return i;
// Path Compression
return parent[i] = find(parent[i]);
}

void unite(int i, int j) {


int root_i = find(i);
int root_j = find(j);
if (root_i != root_j) {
// Union by Rank
if (rank[root_i] < rank[root_j]) {
parent[root_i] = root_j;
} else if (rank[root_i] > rank[root_j]) {
parent[root_j] = root_i;
} else {
parent[root_j] = root_i;
rank[root_i]++;
}
}
}
};

// Kruskal's Minimum Spanning Tree algorithm


int kruskalMinimumSpanningTree(int V, vector<Edge>& edges) {
// 1. Sort edges in non-decreasing order of weight
sort(edges.begin(), edges.end());

DisjointSet disjointSet(V);
int minimumSpanningTreeWeight = 0;
int edgesInTree = 0;
vector<Edge> minimumSpanningTreeEdges; // Optional: to store MST
edges

// 2. Iterate through sorted edges


for (const auto& edge : edges) {
int u = edge.u;
int v = edge.v;
int weight = edge.weight;

// 3. Check if adding this edge creates a cycle


if (disjointSet.find(u) != disjointSet.find(v)) {
// 4. If not, include it in the MST and merge sets
minimumSpanningTreeWeight += weight;
disjointSet.unite(u, v);
minimumSpanningTreeEdges.push_back(edge); // Optional
edgesInTree++;

// Stop if we have V-1 edges


if (edgesInTree == V - 1) {
break;
}
}
}

// Optional: Validate if MST is valid (all nodes connected)


// if (edgesInTree != V - 1) return -1; // Graph not initially
connected

return minimumSpanningTreeWeight;
}

● Complexity Analysis:
○ Time: O(E log E) or O(E log V). Sorting the E edges takes O(E log E) time. The
subsequent loop iterates through E edges, performing two find operations
and potentially one union operation per edge. With optimized DSU, these
operations take nearly constant amortized time, O(α(V)). Thus, the total time
is dominated by the sorting step: O(E log E + E α(V)) ≈ O(E log E).3 Since E can
be up to O(V^2), log E can be up to O(log V^2) = O(2 log V) = O(log V), so O(E
log E) is often written as O(E log V).
○ Space: O(V + E) to store the graph edges and the DSU data structure.167
● Kruskal's vs. Prim's: Kruskal's algorithm's complexity is dominated by edge
sorting, making it potentially more efficient for sparse graphs (where E is closer
to V) compared to Prim's O(E log V) if E is significantly less than V^2.150 Prim's
algorithm might be preferred for dense graphs (E approaches V^2) as its O(E log
V) complexity might outperform O(E log E) in some scenarios, especially with
more advanced heap structures like Fibonacci heaps (O(E + V log V)).150 Kruskal's
processes edges globally based on weight, while Prim's grows the MST locally
from a starting vertex. Kruskal's use of Union-Find naturally connects it to
problems involving component merging and cycle detection.
● Practice Problems:
● Min Cost to Connect All Points 118
● The Earliest Moment When Everyone Become Friends (DSU application, related
logic)
● Supplement: LeetCode 1168. Optimize Water Distribution in a Village.74
LeetCode 1489. Find Critical and Pseudo-Critical Edges in Minimum Spanning
Tree.74

D. Table: MST Algorithm Comparison


Feature Prim's Algorithm Kruskal's Algorithm

Approach Grows MST from a single Adds cheapest non-cycle


vertex edges globally

Data Structures Priority Queue (Min-Heap), Sorted Edge List, Union-Find


Visited Array (DSU)

Time Complexity O(E log V) (with binary heap) O(E log E) or O(E log V) (sort
dominates)

Best For Generally better for Dense Generally better for Sparse
Graphs Graphs

Cycle Detection Implicit (only add edges to Explicit (using Union-Find)


non-MST nodes)

Works cited

1. Graph theory - Wikipedia, accessed April 14, 2025,


https://en.wikipedia.org/wiki/Graph_theory
2. Graph in Data Structure | Types & Explanation - Simplilearn.com, accessed April
14, 2025, https://www.simplilearn.com/tutorials/data-structure-tutorial/graphs-
in-data-structure
3. Graph Theory | Discrete Mathematics Class Notes - Fiveable, accessed April 14,
2025, https://library.fiveable.me/discrete-mathematics/unit-8
4. Graph Theory Fundamentals for Beginners: An Easy Guide, accessed April 14,
2025, https://www.numberanalytics.com/blog/graph-theory-fundamentals-
beginners-guide
5. Graphs and Networks for Beginners - Hypermode, accessed April 14, 2025,
https://hypermode.com/blog/graphs-and-networks
6. Graph Theory Fundamentals - Tutorialspoint, accessed April 14, 2025,
https://www.tutorialspoint.com/graph_theory/graph_theory_fundamentals.htm
7. Graph Fundamentals | An Explorer of Things, accessed April 14, 2025,
https://chih-ling-hsu.github.io/2020/05/12/Graph
8. An Introduction to Graph Theory - DataCamp, accessed April 14, 2025,
https://www.datacamp.com/tutorial/introduction-to-graph-theory
9. Implementing Graphs: Edge List, Adjacency List, Adjacency Matrix - AlgoDaily,
accessed April 14, 2025, https://algodaily.com/lessons/implementing-graphs-
edge-list-adjacency-list-adjacency-matrix
10. Graph Adjacency Matrix (With code examples in C++, Java and Python) -
Programiz, accessed April 14, 2025, https://www.programiz.com/dsa/graph-
adjacency-matrix
11. traversy-js-challenges/08-binary-trees-graphs/11-adjacency-matrix-adjacency-
list/readme.md at main - GitHub, accessed April 14, 2025,
https://github.com/bradtraversy/traversy-js-challenges/blob/main/08-binary-
trees-graphs/11-adjacency-matrix-adjacency-list/readme.md
12. Graph Representation in C++ - Tutorial - takeUforward, accessed April 14, 2025,
https://takeuforward.org/graph/graph-representation-in-c/
13. C++ Program to Represent Graph Using Adjacency Matrix - Tutorialspoint,
accessed April 14, 2025, https://www.tutorialspoint.com/cplusplus-program-to-
represent-graph-using-adjacency-matrix
14. Adjacency Matrix and std::mdspan, C++23 - C++ Stories, accessed April 14, 2025,
https://www.cppstories.com/2025/cpp23_mdspan_adj/
15. Create Adjancency Matrix with C++ - SheCodes Athena, accessed April 14, 2025,
https://www.shecodes.io/athena/9971-create-adjancency-matrix-with-c
16. Graphs Representations - Adjacency Lists vs Adjacency Matrix - YouTube,
accessed April 14, 2025, https://www.youtube.com/watch?v=EQsZJCsNOSc
17. Floyd-Warshall Algorithm - Programiz, accessed April 14, 2025,
https://www.programiz.com/dsa/floyd-warshall-algorithm
18. Find the shortest path with Floyd algorithm - c++ - Stack Overflow, accessed
April 14, 2025, https://stackoverflow.com/questions/31053360/find-the-shortest-
path-with-floyd-algorithm
19. Implementation of Adjacent Matrix with 2D vectors c++ - Stack Overflow,
accessed April 14, 2025,
https://stackoverflow.com/questions/16440721/implementation-of-adjacent-
matrix-with-2d-vectors-c
20. What is better, adjacency lists or adjacency matrices for graph problems in C++?,
accessed April 14, 2025, https://stackoverflow.com/questions/2218322/what-is-
better-adjacency-lists-or-adjacency-matrices-for-graph-problems-in-c
21. Big O Complexity for Graphs: Adjacency Matrix vs Adjacency List - DEV
Community, accessed April 14, 2025, https://dev.to/akashdeep/big-o-
complexity-for-graphs-adjacency-matrix-vs-adjacency-list-3akf
22. Understanding Graphs in JavaScript: Adjacency Matrix vs. Adjacency List - Code
& Chaos, accessed April 14, 2025,
https://imkarthikeyans.hashnode.dev/understanding-graphs-in-javascript-
adjacency-matrix-vs-adjacency-list
23. Time and Space Complexity of Adjacency Matrix and List | Baeldung on
Computer Science, accessed April 14, 2025,
https://www.baeldung.com/cs/adjacency-matrix-list-complexity
24. Overview - Daffodil International University, accessed April 14, 2025,
https://pd.daffodilvarsity.edu.bd/course/material/222/pdf_content
25. When are adjacency lists or matrices the better choice?, accessed April 14, 2025,
https://cs.stackexchange.com/questions/79322/when-are-adjacency-lists-or-
matrices-the-better-choice
26. When is it better to use adjacency matrix vs. adjacency list representation of a
graph? : r/csMajors - Reddit, accessed April 14, 2025,
https://www.reddit.com/r/csMajors/comments/h8y8nv/when_is_it_better_to_use
_adjacency_matrix_vs/
27. Breadth-first Search (BFS) Algorithm Explained - Interview kickstart, accessed
April 14, 2025, https://interviewkickstart.com/blogs/learn/breadth-first-search-
algorithm
28. Learn DFS ( Depth First Search Algorithm ) - Interview kickstart, accessed April
14, 2025, https://interviewkickstart.com/blogs/learn/depth-first-search-algorithm
29. Adjacency List (With Code in C, C++, Java and Python) - Programiz, accessed
April 14, 2025, https://www.programiz.com/dsa/graph-adjacency-list
30. Adjacency list representation using vector of vectors(2D vector) in C++ - Stack
Overflow, accessed April 14, 2025,
https://stackoverflow.com/questions/41530010/adjacency-list-representation-
using-vector-of-vectors2d-vector-in-c
31. Inputting and Representing an Weighted Undirected graph in adjacency list in
vector of list structure. Easy C++ STL implementation and explanation based on
visual representation. - GitHub Gist, accessed April 14, 2025,
https://gist.github.com/quickgrid/572aa9b3dfb8a71bb424005f9a810a84
32. Dijkstra's Shortest Path Algorithm using priority_queue of STL | GeeksforGeeks,
accessed April 14, 2025, https://www.geeksforgeeks.org/dijkstras-shortest-path-
algorithm-using-priority_queue-stl/
33. Dijkstra's Algorithm - Using Priority Queue : G-32 - Tutorial - takeUforward,
accessed April 14, 2025, https://takeuforward.org/data-structure/dijkstras-
algorithm-using-priority-queue-g-32/
34. Dijkstra on sparse graphs - Algorithms for Competitive Programming, accessed
April 14, 2025, https://cp-algorithms.com/graph/dijkstra_sparse.html
35. C++ Shortest Path - Dijkstra PQ Implementation, Bellman-Ford Code As Backup,
and Floyd Warshall - /src$ make, accessed April 14, 2025,
https://www.srcmake.com/home/cpp-shortest-path-dijkstra
36. Breadth First Search (BFS): Level Order Traversal - Tutorial - takeUforward,
accessed April 14, 2025, https://takeuforward.org/graph/breadth-first-search-
bfs-level-order-traversal/
37. Depth First Search (DFS) - Tutorial - takeUforward, accessed April 14, 2025,
https://takeuforward.org/data-structure/depth-first-search-dfs/
38. C++ Vectors and Linked Lists : r/cpp_questions - Reddit, accessed April 14, 2025,
https://www.reddit.com/r/cpp_questions/comments/100p5u1/c_vectors_and_link
ed_lists/
39. Why adjacency list uses array of vectors and not vector of vectors in graphs in c+
+?, accessed April 14, 2025, https://stackoverflow.com/questions/73260725/why-
adjacency-list-uses-array-of-vectors-and-not-vector-of-vectors-in-graphs-in
40. Detect Cycle in an Undirected Graph (using BFS) - Tutorial - takeUforward,
accessed April 14, 2025, https://takeuforward.org/data-structure/detect-cycle-
in-an-undirected-graph-using-bfs/
41. Why are graphs represented as adjacency lists instead of adjacency sets?,
accessed April 14, 2025, https://cs.stackexchange.com/questions/146553/why-
are-graphs-represented-as-adjacency-lists-instead-of-adjacency-sets
42. 2.Data Formats for Networks, accessed April 14, 2025,
https://dshizuka.github.io/networkanalysis/02_dataformats.html
43. Breadth First Search Tutorials & Notes | Algorithms - HackerEarth, accessed April
14, 2025, https://www.hackerearth.com/practice/algorithms/graphs/breadth-
first-search/tutorial/
44. BFS (Breadth-First Search) Algorithm - WsCube Tech, accessed April 14, 2025,
https://www.wscubetech.com/resources/dsa/bfs-algorithm
45. BFS Graph Algorithm(With code in C, C++, Java and Python) - Programiz,
accessed April 14, 2025, https://www.programiz.com/dsa/graph-bfs
46. Breadth-First Search (BFS) - Shortest Paths in Unweighted Graphs | Interview
Cake, accessed April 14, 2025,
https://www.interviewcake.com/concept/python/bfs?
47. When to Use Depth First Search vs Breadth First Search - Hypermode, accessed
April 14, 2025, https://hypermode.com/blog/20240723-depth-first-search-vs-
breadth-first-search
48. Solving LeetCode Problems Using Graph Theory - HackerNoon, accessed April
14, 2025, https://hackernoon.com/solving-leetcode-problems-using-graph-
theory
49. A Beginners guid to BFS and DFS - LeetCode Discuss, accessed April 14, 2025,
https://leetcode.com/discuss/study-guide/1072548/A-Beginners-guid-to-BFS-
and-DFS
50. Graph algorithms + problems to practice - LeetCode Discuss, accessed April 14,
2025, https://leetcode.com/discuss/study-guide/1326900/
51. All Graph Algorithms - One Stop Destination [Standard Implementations] -
LeetCode, accessed April 14, 2025,
https://leetcode.com/discuss/study-guide/6132428/All-Graph-Algorithms-One-
Stop-Destination-Standard-Implementations
52. Breadth First Search Algorithm Explained With C++ Examples - YouTube,
accessed April 14, 2025, https://www.youtube.com/watch?v=cDS5ZTeANZM
53. Connected Components in a Graph | Baeldung on Computer Science, accessed
April 14, 2025, https://www.baeldung.com/cs/graph-connected-components
54. Finding the Shortest Path in Graphs with BFS Algorithm | CodeSignal Learn,
accessed April 14, 2025, https://codesignal.com/learn/courses/mastering-
graphs-in-python/lessons/finding-the-shortest-path-in-graphs-with-bfs-
algorithm
55. Shortest Path In Unweighted Graphs, accessed April 14, 2025,
https://blog.heycoach.in/shortest-path-in-unweighted-graphs/
56. Shortest Paths with Unweighted Edges - USACO Guide, accessed April 14, 2025,
https://usaco.guide/gold/unweighted-shortest-paths?lang=java
57. Breadth First Search, Dijkstra's Algorithm for Shortest Paths, accessed April 14,
2025, https://courses.grainger.illinois.edu/cs374al1/sp2023/slides/17-shortest-
paths.pdf
58. Finding shortest path unweighted graph using BFS (javascript) - Stack Overflow,
accessed April 14, 2025, https://stackoverflow.com/questions/52901344/finding-
shortest-path-unweighted-graph-using-bfs-javascript
59. Breadth First Search - Finding Shortest Paths in Unweighted Graphs - YouTube,
accessed April 14, 2025, https://www.youtube.com/watch?v=T_m27bhVQQQ
60. Graphs | All Algorithms | Theroy And Implementation - LeetCode Discuss,
accessed April 14, 2025,
https://leetcode.com/discuss/interview-question/3365918/Graphs-or-All-
Algorithms-or-Theroy-And-Implementation
61. Check Vertices in Undirected Graph - Tutorialspoint, accessed April 14, 2025,
https://www.tutorialspoint.com/queries-to-check-if-vertices-x-and-y-are-in-
the-same-connected-component-of-an-undirected-graph
62. 323. Number of Connected Components in an Undirected Graph - In-Depth
Explanation, accessed April 14, 2025, https://algo.monster/liteproblems/323
63. Search for connected components in a graph - Algorithms for Competitive
Programming, accessed April 14, 2025, https://cp-algorithms.com/graph/search-
for-connected-components.html
64. C++ implementation of the algorithm to find number of connected components
in a graph. · Issue #6555 · OpenGenus/cosmos - GitHub, accessed April 14, 2025,
https://github.com/OpenGenus/cosmos/issues/6555
65. Cycle Detection in an Undirected Graph - TheJat.in, accessed April 14, 2025,
https://thejat.in/code/cycle-detection-in-an-undirected-graph
66. G-11. Detect a Cycle in an Undirected Graph using BFS | C++ | Java - YouTube,
accessed April 14, 2025, https://www.youtube.com/watch?v=BPlrALf1LDU
67. Finding a cycle and saving its vertices in an undirected, unweighted graph using
BFS, accessed April 14, 2025,
https://stackoverflow.com/questions/69680969/finding-a-cycle-and-saving-its-
vertices-in-an-undirected-unweighted-graph-using
68. 15 Cycle detection In Undirected graph Using BFS - YouTube, accessed April 14,
2025, https://www.youtube.com/watch?v=1ZWTKJpIvpE
69. Interview question - detect a cycle in an undirected graph? : r/algorithms -
Reddit, accessed April 14, 2025,
https://www.reddit.com/r/algorithms/comments/b8j3rs/interview_question_detec
t_a_cycle_in_an/
70. BFS and DFS Graph Problems: Easy to Medium Difficulty - LeetCode Discuss,
accessed April 14, 2025,
https://leetcode.com/discuss/interview-question/5039797/BFS-and-DFS-Graph-
Problems%3A-Easy-to-Medium-Difficulty/
71. Clone Graph: Ace LeetCode with DFS & BFS - Sean Coughlin's Blog, accessed
April 14, 2025, https://blog.seancoughlin.me/mastering-the-clone-graph-
problem-on-leetcode-a-comprehensive-guide
72. LeetCode Problems by Official Solution Category - Software Engineering
Handbook, accessed April 14, 2025, https://dwf.dev/docs/learning-resources/lc-
solution-categories
73. LeetCode 133. Clone Graph Solution | DFS & BFS Approaches | Must-Know Graph
Problem for Interviews - YouTube, accessed April 14, 2025,
https://www.youtube.com/watch?v=FhwfoL9JI_8
74. List of graph algorithms for coding interview - LeetCode Discuss, accessed April
14, 2025, https://leetcode.com/discuss/general-discussion/753236/list-of-graph-
algorithms-for-coding-interview
75. Depth First Search (DFS) – Iterative and Recursive Implementation - Maxnilz,
accessed April 14, 2025, https://maxnilz.com/docs/001-ds/graph/001-deep-first-
search/
76. Depth First Search Tutorials & Notes | Algorithms - HackerEarth, accessed April
14, 2025, https://www.hackerearth.com/practice/algorithms/graphs/depth-first-
search/tutorial/
77. Depth First Search (DFS) C++ Program To Traverse A Graph Or Tree, accessed
April 14, 2025, https://www.softwaretestinghelp.com/cpp-dfs-program-to-
traverse-graph/
78. Depth First Search or DFS for a Graph | GeeksforGeeks, accessed April 14, 2025,
https://www.geeksforgeeks.org/depth-first-search-or-dfs-for-a-graph/
79. c++ - Iterative DFS vs Recursive DFS and different elements order - Stack
Overflow, accessed April 14, 2025,
https://stackoverflow.com/questions/9201166/iterative-dfs-vs-recursive-dfs-
and-different-elements-order
80. Iterative Depth First Search for cycle detection on directed graphs, accessed
April 14, 2025, https://cs.stackexchange.com/questions/121831/iterative-depth-
first-search-for-cycle-detection-on-directed-graphs
81. Checking a graph for acyclicity and finding a cycle in O(M) - Algorithms for
Competitive Programming, accessed April 14, 2025,
https://cp-algorithms.com/graph/finding-cycle.html
82. Can a 3 Color DFS be used to identify cycles (not just detect them)?, accessed
April 14, 2025, https://cs.stackexchange.com/questions/86148/can-a-3-color-
dfs-be-used-to-identify-cycles-not-just-detect-them
83. Detecting a cycle in a directed graph using DFS? - Stack Overflow, accessed
April 14, 2025, https://stackoverflow.com/questions/31542031/detecting-a-cycle-
in-a-directed-graph-using-dfs
84. Detect Cycle in an Undirected Graph (using DFS) - Tutorial - takeUforward,
accessed April 14, 2025, https://takeuforward.org/data-structure/detect-cycle-
in-an-undirected-graph-using-dfs/
85. DETECTING CYCLE IN A GRAPH - Expert Mentoring, Customized Solutions -
Venkys.io, accessed April 14, 2025, https://venkys.io/articles/details/detecting-
cycle-in-a-graph
86. Cycle in an undirected graph using dfs - c++ - Stack Overflow, accessed April 14,
2025, https://stackoverflow.com/questions/49223190/cycle-in-an-undirected-
graph-using-dfs
87. 16.4.2 DFS and cycle detection: Topological sorting using DFS, accessed April 14,
2025,
https://courses.grainger.illinois.edu/cs374/fa2020/lec_prerec/16/16_4_2_0.pdf
88. Topological Sort Using DFS, accessed April 14, 2025,
https://blog.heycoach.in/topological-sort-using-dfs/
89. Topological Sorting - Algorithms for Competitive Programming, accessed April
14, 2025, https://cp-algorithms.com/graph/topological-sort.html
90. Cycle Detection and Topological Sort Algorithm | Labuladong Algo Notes,
accessed April 14, 2025,
https://labuladong.online/algo/en/data-structure/topological-sort/
91. Algorithms for Detecting Cycles in Graphs: A Comprehensive Guide -
AlgoCademy, accessed April 14, 2025, https://algocademy.com/blog/algorithms-
for-detecting-cycles-in-graphs-a-comprehensive-guide/
92. Why use DFS to find cycles in an undirected graph and topological sorting to find
cycles in a directed graph? - Stack Overflow, accessed April 14, 2025,
https://stackoverflow.com/questions/16779699/why-use-dfs-to-find-cycles-in-
an-undirected-graph-and-topological-sorting-to-fin
93. BFS and DFS applications - Tyler Moore, accessed April 14, 2025,
https://tylermoore.ens.utulsa.edu/courses/cse3353/slides/l07-handout.pdf
94. Chapter 11 Depth-First Search, accessed April 14, 2025,
https://www.cs.cmu.edu/afs/cs/academic/class/15210-f14/www/lectures/graph-
dfs.pdf
95. Union-Find Algorithm | Set 1 (Detect Cycle in an Undirected Graph) |
GeeksforGeeks, accessed April 14, 2025, https://www.youtube.com/watch?
v=mHz-mx-8lJ8
96. Apply DFS for Topological Sorting of Directed Acyclic Graph in C++ -
Tutorialspoint, accessed April 14, 2025,
https://www.tutorialspoint.com/cplusplus-program-to-apply-dfs-to-perform-
the-topological-sorting-of-a-directed-acyclic-graph
97. Topological Sort Using DFS - Tutorial - takeUforward, accessed April 14, 2025,
https://takeuforward.org/data-structure/topological-sort-using-dfs/
98. Topological sort using DFS without recursion - c++ - Stack Overflow, accessed
April 14, 2025, https://stackoverflow.com/questions/20153488/topological-sort-
using-dfs-without-recursion
99. Cyclic graph into Topological Sort? : r/algorithms - Reddit, accessed April 14,
2025,
https://www.reddit.com/r/algorithms/comments/aex403/cyclic_graph_into_topol
ogical_sort/
100. Introduction to Topological Sort - LeetCode Discuss, accessed April 14, 2025,
https://leetcode.com/discuss/general-discussion/1078072/introduct
101. Leetcode/Algorithm/Topology_Sort.md at master - GitHub, accessed April 14,
2025,
https://github.com/UmassJin/Leetcode/blob/master/Algorithm/Topology_Sort.m
d
102. Connected Components in an undirected graph - c++ - Stack Overflow,
accessed April 14, 2025,
https://stackoverflow.com/questions/24119528/connected-components-in-an-
undirected-graph
103. DFS to find the number of connected components and displaying a cycle -
Reddit, accessed April 14, 2025,
https://www.reddit.com/r/cpp_questions/comments/k95aht/dfs_to_find_the_nu
mber_of_connected_components/
104. Strongly Connected Components - Neo4j Graph Data Science, accessed April
14, 2025,
https://neo4j.com/docs/graph-data-science/current/algorithms/strongly-
connected-components/
105. Number of Provinces - LeetCode, accessed April 14, 2025,
https://leetcode.com/problems/number-of-provinces/
106. Distilled • LeetCode • Topological Sort - aman.ai, accessed April 14, 2025,
https://aman.ai/code/top-sort/
107. Topological Sort (w/ DFS) + Course Schedule LeetCode - Reddit, accessed April
14, 2025,
https://www.reddit.com/r/leetcode/comments/dupmul/topological_sort_w_dfs_c
ourse_schedule_leetcode/
108. Graph For Beginners [Problems | Pattern | Sample Solutions] - LeetCode
Discuss, accessed April 14, 2025,
https://leetcode.com/discuss/study-guide/655708/Graph-For-Beginners-
Problems-or-Pattern-or-Sample-Solutions
109. Dijkstra Algorithm: Example, Time Complexity, Code - WsCube Tech, accessed
April 14, 2025, https://www.wscubetech.com/resources/dsa/dijkstra-algorithm
110. Shortest Paths - Algorithms, 4th Edition, accessed April 14, 2025,
https://algs4.cs.princeton.edu/44sp/
111. Shortest path: Dijkstra's algorithm, Bellman-Ford algorithm – Clayton Cafiero,
accessed April 14, 2025,
https://www.uvm.edu/~cbcafier/cs2240/content/13_graph_algos/01_shortest_pat
h.html
112. Bellman Ford's Algorithm - Programiz, accessed April 14, 2025,
https://www.programiz.com/dsa/bellman-ford-algorithm
113. Bellman-Ford - finding shortest paths with negative weights - Algorithms for
Competitive Programming, accessed April 14, 2025,
https://cp-algorithms.com/graph/bellman_ford.html
114. Floyd Warshall Algorithm (All-Pairs Shortest Paths) - WsCube Tech, accessed
April 14, 2025, https://www.wscubetech.com/resources/dsa/floyd-warshall-
algorithm
115. Bellman–Ford algorithm - Wikipedia, accessed April 14, 2025,
https://en.wikipedia.org/wiki/Bellman%E2%80%93Ford_algorithm
116. Shortest Paths with Negative Edge Weights - USACO Guide, accessed April 14,
2025, https://usaco.guide/adv/sp-neg
117. All graph algorithms with a template - Dijkstra | Bellman-Ford | Floyd-Warshall |
Prims | Kruskal - LeetCode Discuss, accessed April 14, 2025,
https://leetcode.com/discuss/interview-question/6153851/All-graph-algorithms-
with-a-template-Dijkstra-or-Bellman-Ford-or-Floyd-Warshall-or-Prims-or-
Kruskal
118. Graph Algorithms One Place | Dijkstra | Bellman Ford | Floyd Warshall | Prims |
Kruskals | DSU - LeetCode Discuss, accessed April 14, 2025,
https://leetcode.com/discuss/study-guide/969327/Graph-Algorithms-One-
Place-or-Dijkstra-or-Bellman-Ford-or-Floyd-Warshall-or-Prims-or-Kruskals-or-
DSU
119. Shortest Path Floyd Warshall Algorithm SYCL Implementation on GPU - Intel,
accessed April 14, 2025,
https://www.intel.com/content/www/us/en/developer/articles/technical/shortest-
path-sycl-based-floyd-warshall-on-gpu.html
120. Floyd–Warshall algorithm - Wikipedia, accessed April 14, 2025,
https://en.wikipedia.org/wiki/Floyd%E2%80%93Warshall_algorithm
121. Mastering Graph Theory for Coding Interviews: Key Concepts and Strategies -
AlgoCademy, accessed April 14, 2025, https://algocademy.com/blog/mastering-
graph-theory-for-coding-interviews-key-concepts-and-strategies/
122. algs4.cs.princeton.edu, accessed April 14, 2025,
https://algs4.cs.princeton.edu/44sp/#:~:text=Dijkstra's%20algorithm%20solves
%20the%20single,(in%20the%20worst%20case).
123. Dijkstra's algorithm - Wikipedia, accessed April 14, 2025,
https://en.wikipedia.org/wiki/Dijkstra%27s_algorithm
124. 1 Non-negative weights - László Kozma, accessed April 14, 2025,
http://www.lkozma.net/notes/sssp_notes.pdf
125. Can dijkstra's algorithm work for graph with negative edges but with no
negative cycles? : r/compsci - Reddit, accessed April 14, 2025,
https://www.reddit.com/r/compsci/comments/1cnptgi/can_dijkstras_algorithm_w
ork_for_graph_with/
126. Bellman Ford Algorithm: G-41 - Tutorial - takeUforward, accessed April 14, 2025,
https://takeuforward.org/data-structure/bellman-ford-algorithm-g-41/
127. Floyd–Warshall algorithm explanation in 9 minutes - YouTube, accessed April 14,
2025, https://www.youtube.com/watch?
v=NdBHw5mqIZE&pp=0gcJCdgAo7VqN5tD
128. Finding a Negative Cycle in the Graph - Algorithms for Competitive
Programming, accessed April 14, 2025, https://cp-algorithms.com/graph/finding-
negative-cycle-in-graph.html
129. How to Detect Negative cycle in Bellman Ford Algorithm? - Stack Overflow,
accessed April 14, 2025, https://stackoverflow.com/questions/62385300/how-to-
detect-negative-cycle-in-bellman-ford-algorithm
130. What exactly happens in the Bellman-Ford Algorithm if there is a negative
weigth cycle?, accessed April 14, 2025,
https://stackoverflow.com/questions/15840495/what-exactly-happens-in-the-
bellman-ford-algorithm-if-there-is-a-negative-weigth
131. Dijkstra's shortest path algorithm using set | GeeksforGeeks, accessed April 14,
2025, https://www.geeksforgeeks.org/dijkstras-shortest-path-algorithm-using-
set-in-stl/
132. Why doesn't Dijkstra's algorithm work for negative weight edges? - Stack
Overflow, accessed April 14, 2025,
https://stackoverflow.com/questions/13159337/why-doesnt-dijkstras-algorithm-
work-for-negative-weight-edges
133. Does Dijkstra work for this graph with negative weights? : r/compsci - Reddit,
accessed April 14, 2025,
https://www.reddit.com/r/compsci/comments/1gmmarr/does_dijkstra_work_for_
this_graph_with_negative/
134. Implementation of A* - Red Blob Games, accessed April 14, 2025,
https://www.redblobgames.com/pathfinding/a-star/implementation.html
135. priority queue implementation explanation - c++ - Stack Overflow, accessed
April 14, 2025, https://stackoverflow.com/questions/20944305/priority-queue-
implementation-explanation
136. How important is learning Dijkstra's Algorithm for interviews? : r/leetcode -
Reddit, accessed April 14, 2025,
https://www.reddit.com/r/leetcode/comments/1f2uhsu/how_important_is_learnin
g_dijkstras_algorithm_for/
137. Floyd-Warshall: all shortest paths - Stack Overflow, accessed April 14, 2025,
https://stackoverflow.com/questions/11370041/floyd-warshall-all-shortest-paths
138. 4.2 All Pairs Shortest Path (Floyd-Warshall) - Dynamic Programming - YouTube,
accessed April 14, 2025, https://www.youtube.com/watch?v=oNI0rf2P9gE
139. Kruskal's Algorithm - Programiz, accessed April 14, 2025,
https://www.programiz.com/dsa/kruskal-algorithm
140. Minimum Spanning Tree Tutorials & Notes | Algorithms - HackerEarth, accessed
April 14, 2025,
https://www.hackerearth.com/practice/algorithms/graphs/minimum-spanning-
tree/tutorial/
141. Minimum Spanning Tree (MST) in Graph Data Structure - Youcademy, accessed
April 14, 2025, https://youcademy.org/minimum-spanning-trees-in-graphs/
142. Minimum spanning tree - Wikipedia, accessed April 14, 2025,
https://en.wikipedia.org/wiki/Minimum_spanning_tree
143. Minimum spanning trees, accessed April 14, 2025,
https://msp.org/involve/2009/2-4/involve-v2-n4-p06-s.pdf
144. Applications of Minimum Spanning Trees, accessed April 14, 2025,
http://bioinformatics.cs.vt.edu/~murali/teaching/2021-fall-cs4104/lectures/
lecture13-mst-applications.pdf
145. Distributed Minimum Spanning Trees - Stanford University, accessed April 14,
2025,
https://stanford.edu/~rezab/classes/cme323/S15/projects/distributed_minimum_s
panning_trees_report.pdf
146. Inadequacies of Minimum Spanning Trees in Molecular Epidemiology - PMC,
accessed April 14, 2025, https://pmc.ncbi.nlm.nih.gov/articles/PMC3187300/
147. en.wikipedia.org, accessed April 14, 2025,
https://en.wikipedia.org/wiki/Minimum_spanning_tree#:~:text=small%20as
%20possible.-,Applications,for%2C%20as%20mentioned%20above).
148. 6.3 Applications of minimum spanning trees - Graph Theory - Fiveable,
accessed April 14, 2025,
https://library.fiveable.me/graph-theory/unit-6/applications-minimum-spanning-
trees/study-guide/iOCen7zmSVC9rHOF
149. Applications of minimum spanning trees, accessed April 14, 2025,
https://www.utdallas.edu/~besp/teaching/mst-applications.pdf
150. Prim's Algorithm: A Comprehensive Guide to Minimum Spanning Trees –
AlgoCademy Blog, accessed April 14, 2025, https://algocademy.com/blog/prims-
algorithm-a-comprehensive-guide-to-minimum-spanning-trees/
151. Priority queue and Prim's Algorithm - c++ - Stack Overflow, accessed April 14,
2025, https://stackoverflow.com/questions/21022334/priority-queue-and-prims-
algorithm
152. Prim's Algorithm: Example, Time Complexity, Code - WsCube Tech, accessed
April 14, 2025, https://www.wscubetech.com/resources/dsa/prim-algorithm
153. Prim's Algorithm - Minimum Spanning Tree - C++ and Java: G-45 - Tutorial -
takeUforward, accessed April 14, 2025, https://takeuforward.org/data-
structure/prims-algorithm-minimum-spanning-tree-c-and-java-g-45/
154. Priority Queue Implementation In Prim's Algorithm, accessed April 14, 2025,
https://blog.heycoach.in/priority-queue-implementation-in-prims-algorithm/
155. Prim's algorithm - Wikipedia, accessed April 14, 2025,
https://en.wikipedia.org/wiki/Prim%27s_algorithm
156. Prim's algorithm using priority_queue in STL | PrepBytes Blog, accessed April 14,
2025, https://www.prepbytes.com/blog/queues/prims-algorithm-using-
priority_queue-in-stl/
157. Why do we need a priority queue in Prim's Algorithm - Stack Overflow, accessed
April 14, 2025, https://stackoverflow.com/questions/7038581/why-do-we-need-
a-priority-queue-in-prims-algorithm
158. G-45. Prim's Algorithm - Minimum Spanning Tree - C++ and Java - YouTube,
accessed April 14, 2025, https://www.youtube.com/watch?v=mJcZjjKzeqk
159. Min Cost to Connect All Points - LeetCode, accessed April 14, 2025,
https://leetcode.com/problems/min-cost-to-connect-all-points/discuss/
843940/C%2B%2B-MST%3A-Kruskal-%2B-Prim's-%2B-Complete-Graph
160. Kruskal's Algorithm: Key to Minimum Spanning Tree [MST] - Simplilearn.com,
accessed April 14, 2025, https://www.simplilearn.com/tutorials/data-structure-
tutorial/kruskal-algorithm
161. Kruskal's Algorithm and Union-Find, accessed April 14, 2025,
https://web.cs.unlv.edu/larmore/Courses/CSC477/S25/Handouts/unionfnd.pdf
162. 14.7. Kruskal's Algorithm — CS3 Data Structures & Algorithms - OpenDSA,
accessed April 14, 2025,
https://opendsa-server.cs.vt.edu/ODSA/Books/CS3/html/Kruskal.html
163. How to use union-find, minheap, Kruskal's, and a sort algorithm to create a
minimum cost spanning tree? (C++) - Stack Overflow, accessed April 14, 2025,
https://stackoverflow.com/questions/4916287/how-to-use-union-find-minheap-
kruskals-and-a-sort-algorithm-to-create-a-mini
164. Algorithms in Systems Engineering ISE 172 Lecture 22, accessed April 14, 2025,
https://coral.ise.lehigh.edu/~ted/files/ie172/lectures/Lecture22.pdf
165. Union Find Kruskal's Algorithm - YouTube, accessed April 14, 2025,
https://www.youtube.com/watch?v=JZBQLXgSGfs&pp=0gcJCdgAo7VqN5tD
166. Union-Find In Kruskal's Algorithm (MST), accessed April 14, 2025,
https://blog.heycoach.in/union-find-in-kruskals-algorithm-mst/
167. G-47. Kruskal's Algorithm - Minimum Spanning Tree - C++ and Java - YouTube,
accessed April 14, 2025, https://www.youtube.com/watch?v=DMnDM_sxVig
168. Implement Kruskal's Algorithm in C++ - DEV Community, accessed April 14,
2025, https://dev.to/nokha_debbarma/implement-kruskal-s-algorithm-in-c-29cn
169. Union-Find For Cycle Detection, accessed April 14, 2025,
https://blog.heycoach.in/union-find-for-cycle-detection/
170. Union Find Kruskal's Algorithm - YouTube, accessed April 14, 2025,
https://www.youtube.com/watch?v=JZBQLXgSGfs&pp=0gcJCfcAhR29_xXO
171. Kruskal's Algorithm Visually Explained | Disjoint Sets | Union By Rank | Path
Compression, accessed April 14, 2025, https://www.youtube.com/watch?
v=8HeLu8wuLqo
172. Detect cycle in a graph using Kruskal's algorithm - Stack Overflow, accessed
April 14, 2025, https://stackoverflow.com/questions/29998332/detect-cycle-in-a-
graph-using-kruskals-algorithm
173. Does using union-find in Kruskal's algorithm actually affect worst-case runtime?,
accessed April 14, 2025, https://stackoverflow.com/questions/32040718/does-
using-union-find-in-kruskals-algorithm-actually-affect-worst-case-runtime
174. Find Critical and Pseudo-Critical Edges in Minimum Spanning Tree - LeetCode,
accessed April 14, 2025, https://leetcode.com/problems/find-critical-and-
pseudo-critical-edges-in-minim

Advanced Graph Algorithms Study Guide: Part II


This section continues the comprehensive study guide on graph algorithms, focusing
on Topological Sort, Cycle Detection, Connectivity (including Strongly Connected
Components), and the Union-Find data structure. We maintain the established
format, providing conceptual explanations, detailed mechanisms, C++
implementations, complexity analyses, applications, and relevant practice problems.

Section 1: Topological Sort


1.1 Concept and Applications
Topological sorting provides a linear ordering of vertices for a Directed Acyclic
Graph (DAG). In this ordering, for every directed edge from vertex u to vertex v,
vertex u must appear before vertex v.1 This ordering respects the dependencies or
precedence constraints defined by the directed edges within the graph.3 If a graph
contains a cycle, a topological sort is impossible because a cycle implies a circular
dependency where a vertex would need to come both before and after another
vertex in the linear ordering.1 It's important to note that a topological sort for a given
DAG is often not unique; multiple valid linear orderings can exist.1

Topological sorting finds applications in various domains where tasks or events have
prerequisite relationships 4:
● Task Scheduling: Ordering jobs or tasks where certain tasks must be completed
before others can begin (e.g., build systems, project management).4
● Course Scheduling: Determining a valid sequence for taking courses with
prerequisites.5
● Dependency Resolution: Resolving dependencies in software package
management or module loading.5
● Compiler Instruction Scheduling: Ordering instructions while respecting data
dependencies.11
● Data Serialization: Determining the order to serialize objects with
interdependencies.11
● Spreadsheet Cell Evaluation: Calculating cell values based on dependencies on
other cells.

Essentially, any problem that can be modeled as a DAG with precedence constraints
can potentially benefit from topological sorting.11

1.2 Kahn's Algorithm (BFS-based)


Kahn's algorithm provides a method for topological sorting using Breadth-First
Search (BFS) principles.2 It works by iteratively processing nodes that have no
remaining dependencies.
● Mechanism:
1. Compute In-degrees: Calculate the in-degree (number of incoming edges)
for every vertex in the graph. This typically involves iterating through all
edges (u, v) and incrementing the in-degree count for v.2
2. Initialize Queue: Create a queue and enqueue all vertices with an initial in-
degree of 0. These vertices have no prerequisites and can appear first in the
topological order.2
3. Process Queue: While the queue is not empty:
■ Dequeue a vertex u.
■ Add u to the result list (representing the topological order).
■ For each neighbor v of u (i.e., for each edge u -> v):
■ Decrement the in-degree of v. This signifies that the dependency on u
has been satisfied for v.
■ If the in-degree of v becomes 0, enqueue v, as all its prerequisites
have now been met.2
4. Cycle Check: After the loop terminates, if the number of vertices in the result
list is less than the total number of vertices in the graph, it indicates that the
graph contains a cycle, and a topological sort is not possible. Otherwise, the
result list contains a valid topological ordering.2
Kahn's algorithm effectively processes the graph level by level based on
dependencies. Nodes with an in-degree of 0 represent the initial level with no
dependencies. As these nodes are processed, their removal (conceptually) and
the decrementing of their neighbors' in-degrees reveal the next level of nodes
whose dependencies have been fulfilled. The use of a queue naturally facilitates
this breadth-first, level-by-level processing.7

C++ Implementation:

#include <vector>
#include <queue>

// Function implementing Kahn's algorithm for Topological Sorting.


// Parameters:
// V: The number of vertices in the graph.
// adj: Adjacency list representing the graph.
// Returns:
// A vector containing the topological sort order if the graph is
acyclic; otherwise, an empty vector is returned to indicate the
presence of a cycle.
std::vector<int> performTopologicalSortKahn(int V, const
std::vector<std::vector<int>>& adj) {
// 1. Compute the in-degree of each vertex.
std::vector<int> inDegree(V, 0);
for (int u = 0; u < V; ++u) {
for (int v : adj[u]) {
inDegree[v]++;
}
}

// 2. Initialize a queue with vertices having an in-degree of 0.


std::queue<int> queue;
for (int i = 0; i < V; ++i) {
if (inDegree[i] == 0) {
queue.push(i);
}
}

std::vector<int> topologicalOrder; // Stores the resulting


topological order.
int processedVertices = 0; // Counter for processed vertices, used
for cycle detection.

// 3. Process the queue until it is empty.


while (!queue.empty()) {
int u = queue.front();
queue.pop();
topologicalOrder.push_back(u); // Append the dequeued vertex
to the result.
processedVertices++;

// Iterate over the neighbors of the dequeued vertex and


decrement their in-degree.
for (int v : adj[u]) {
// If decrementing the in-degree results in 0, enqueue the
neighbor.
if (--inDegree[v] == 0) {
queue.push(v);
}
}
}

// 4. Check for the presence of cycles.


if (processedVertices != V) {
// The graph contains a cycle; topological sorting is not
possible.
return {}; // Return an empty vector to signify a cycle.
}

return topologicalOrder; // Return the computed topological sort


order.
}

● Complexity Analysis:
○ Time Complexity: O(V + E). Calculating initial in-degrees involves iterating
through all edges (O(E)) and vertices (O(V)). Initializing the queue takes O(V).
The main while loop processes each vertex and each edge exactly once.
Enqueue and dequeue operations take O(1) amortized time. Therefore, the
total time complexity is dominated by scanning vertices and edges, resulting
in O(V + E).7
○ Space Complexity: O(V + E) or O(V). Storing the adjacency list requires O(V
+ E) space. The in_degree array requires O(V) space. The queue can hold up
to O(V) vertices in the worst case. The result vector also requires O(V) space.
Thus, the auxiliary space complexity (beyond the input graph representation)
is O(V).12 If considering the adjacency list as part of the input, the total space
is O(V + E).

1.3 DFS-based Algorithm


An alternative approach to topological sorting utilizes Depth-First Search (DFS).1
● Mechanism:
1. Initialization: Maintain a visited status for each vertex (e.g., a boolean vector
initialized to false) and a container (like a std::stack or std::vector) to store
the topological order.
2. Main Loop: Iterate through all vertices v from 0 to V-1. If v has not been
visited, initiate a DFS traversal starting from v.
3. DFS Traversal (dfs_topo):
■ Mark the current vertex u as visited.
■ Recursively call dfs_topo for all unvisited neighbors w of u.
■ Crucially, after the recursive calls for all neighbors of u have
returned (meaning u and all its descendants have been fully
explored), add u to the topological sort container. If using a stack,
push u onto the stack.1 If using a list, append u to the list.
4. Final Order: If a stack was used, pop elements from the stack sequentially;
the resulting sequence is the topological order. If a list was used, reverse the
list to obtain the topological order.1
The correctness of this approach stems from the properties of DFS finishing
times. A vertex u finishes (i.e., the recursive call dfs_topo(u) returns) only after all
vertices reachable from it have been explored and finished. Consequently, if
there is an edge u -> v, vertex v must finish before vertex u finishes. By adding
vertices to the result container after their recursive calls complete, we ensure
that dependents (v) are added before their prerequisites (u). The final reversal
(or stack popping) yields the correct u before v ordering.1Note that this basic DFS
approach assumes the input graph is a DAG. To explicitly detect cycles, the DFS
must be augmented (e.g., using a three-state coloring scheme as discussed in
Section 2.2) to identify back edges. If a back edge is detected, a topological sort
is impossible.20

C++ Implementation:

#include <vector>
#include <stack>
#include <algorithm> // For std::reverse (if using vector instead of
stack)

// Function: Depth-First Search Topological Sort Helper


// Parameters:
// u: The current vertex.
// adj: The adjacency list representing the graph.
// visited: A vector to track visited vertices.
// st: A stack to store the topological order.
// Description: Performs a depth-first search to assist in topological
sorting.
void depthFirstSearchTopologicalSortHelper(int u, const
std::vector<std::vector<int>>& adj, std::vector<bool>& visited,
std::stack<int>& st) {
visited[u] = true; // Mark the current vertex as visited.

// Iterate over all adjacent vertices.


for (int v : adj[u]) {
if (!visited[v]) {
depthFirstSearchTopologicalSortHelper(v, adj, visited,
st);
}
// Note: Detection of cycles requires an additional check,
potentially using a recursion stack tracker or a three-state visited
array.
}
// Push the current vertex to the stack after all its dependent
vertices have been processed.
st.push(u);
}

// Function: Topological Sort using Depth-First Search


// Parameters:
// V: The number of vertices in the graph.
// adj: The adjacency list representing the graph.
// Returns: A vector containing the topological order or an empty
vector if a cycle is detected (requires cycle detection
implementation).
std::vector<int> topologicalSortDepthFirstSearch(int V, const
std::vector<std::vector<int>>& adj) {
std::stack<int> st; // Stack to store the resultant topological
order.
std::vector<bool> visited(V, false); // Vector to track visited
vertices.

// Invoke the recursive helper function for each vertex.


for (int i = 0; i < V; ++i) {
if (!visited[i]) {
depthFirstSearchTopologicalSortHelper(i, adj, visited,
st);
}
}

std::vector<int> result;
// Retrieve the topological order by popping vertices from the
stack.
while (!st.empty()) {
result.push_back(st.top());
st.pop();
}

// Basic depth-first search topological sort assumes a Directed


Acyclic Graph (DAG). Cycle detection should be incorporated for
robustness.
// If a cycle is detected in
depthFirstSearchTopologicalSortHelper, return an empty vector.
return result;
}

1

● Complexity Analysis:
○ Time Complexity: O(V + E). The DFS algorithm visits each vertex and
traverses each edge exactly once.1 Pushing V elements onto the stack and
popping them takes O(V) time. Thus, the overall complexity is O(V + E).
○ Space Complexity: O(V + E) or O(V). Storing the adjacency list requires O(V
+ E). The visited array requires O(V). The stack (or result vector) requires
O(V). The depth of the recursion stack can reach O(V) in the worst case (e.g.,
a long chain). Therefore, the auxiliary space complexity is O(V).1

1.4 Practice Problems (Topological Sort / Cycle Detection in DAGs)


The following LeetCode problems involve topological sorting or related concepts like
cycle detection in directed graphs:
● 207. Course Schedule (Medium): Determine if a valid course schedule exists
(cycle detection).1
● 210. Course Schedule II (Medium): Return a valid course schedule if one exists
(topological sort).1
● 269. Alien Dictionary (Hard): Infer character order from a list of sorted words
(graph construction + topological sort).10
● 2115. Find All Possible Recipes from Given Supplies (Medium): Model
dependencies as a DAG and find reachable nodes using topological sort
principles.
● 1136. Parallel Courses (Hard): Find the minimum number of semesters required
(longest path in DAG via topological sort).
● 2050. Parallel Courses III (Hard): Calculate earliest finish times for tasks with
dependencies (topological sort variant).
● 444. Sequence Reconstruction (Medium): Check if a given sequence is the
unique topological sort of a graph derived from subsequences.10
● 1203. Sort Items by Groups Respecting Dependencies (Hard): Perform
topological sort at two levels (items within groups and groups themselves).10
● 802. Find Eventual Safe States (Medium): Identify nodes that are not part of
any cycle (related to cycle detection in directed graphs).27

Section 2: Cycle Detection


Detecting cycles is a fundamental problem in graph theory with applications in
various domains, including identifying dependencies, deadlocks, and validating graph
structures.17 A cycle is essentially a path that starts and ends at the same vertex,
traversing at least one edge.28 The detection methods differ slightly between directed
and undirected graphs.

2.1 Concept
● Undirected Cycle: A path in an undirected graph starting and ending at the
same vertex, using distinct edges (and typically distinct intermediate vertices).28
● Directed Cycle: A path in a directed graph that follows the direction of the
edges and returns to the starting vertex.28

2.2 Directed Graphs: DFS (3-State/Visited+Recursion Stack)


Detecting cycles in directed graphs requires distinguishing between paths that revisit
already fully explored parts of the graph and paths that loop back to a node currently
under exploration.
● Mechanism:
This approach uses three states to track the status of each node during the DFS
traversal:
1. WHITE (Not Visited): The node has not been encountered yet.
2. GRAY (Visiting / On Recursion Stack): The node is currently being explored;
it's on the active recursion path.
3. BLACK (Visited / Fully Explored): The node and all its descendants have
been fully explored, and the DFS call for it has finished. 27
The DFS proceeds as follows: Start DFS from an unvisited (WHITE) node. Mark it
GRAY. Explore its neighbors. If a neighbor is WHITE, recursively call DFS on it. If
the recursive call detects a cycle, propagate the result. If a neighbor is GRAY, a
back edge to an ancestor on the current recursion path has been found,
indicating a cycle. Return true.21 If a neighbor is BLACK, it represents a cross or
forward edge to a part of the graph already fully explored from this path's
perspective; this does not indicate a cycle in the current path, so continue
exploration. After exploring all neighbors of the current node, mark it BLACK.27The
necessity of three states arises because simply marking a node as "visited" (a
two-state approach) is insufficient in directed graphs. An edge to an already
"visited" node could be a forward edge or a cross edge to a different, already
completed DFS branch, neither of which forms a cycle with the current path. Only
an edge pointing back to a node currently on the recursion stack (GRAY)
confirms a cycle.33

C++ Implementation:

#include <vector>

// Enumeration to represent the states for Depth-First Search (DFS)


cycle detection in directed graphs.
enum class State { WHITE, GRAY, BLACK }; // WHITE=Unvisited,
GRAY=Visiting, BLACK=Visited

// Function for DFS-based cycle detection.


// Parameters:
// u: The current vertex.
// visited: A vector indicating the state (WHITE, GRAY, BLACK) of
each vertex.
// adj: The adjacency list representing the graph.
// Returns:
// True if a cycle is detected, false otherwise.
bool detectCycleDirectedDFS_Util(int u, std::vector<State>& visited,
const std::vector<std::vector<int>>& adj) {
visited[u] = State::GRAY; // Mark the current node as being
visited.

for (int v : adj[u]) {


if (visited[v] == State::WHITE) { // If the neighbor is
unvisited.
if (detectCycleDirectedDFS_Util(v, visited, adj)) {
return true; // Cycle detected in the subtree.
}
} else if (visited[v] == State::GRAY) { // If the neighbor is
currently being visited.
return true; // Cycle detected due to a back edge.
}
}

visited[u] = State::BLACK; // Mark the current node as visited.


return false; // No cycle detected.
}

// Function to detect cycles in a directed graph using DFS.


// Parameters:
// V: The number of vertices in the graph.
// adj: The adjacency list representation of the graph.
// Returns:
// True if a cycle is detected, false otherwise.
bool detectCycleDirectedDFS(int V, const
std::vector<std::vector<int>>& adj) {
std::vector<State> visited(V, State::WHITE); // Initialize all
nodes as unvisited.
for (int i = 0; i < V; ++i) {
if (visited[i] == State::WHITE) { // If the node is unvisited.
if (detectCycleDirectedDFS_Util(i, visited, adj)) {
return true; // Cycle detected.
}
}
}
return false; // No cycle detected in the graph.
}

27
● Complexity Analysis:
○ Time: O(V + E). Standard DFS complexity, as each vertex and edge is visited
once.27
○ Space: O(V). Required for the visited state vector and the recursion call stack
(which can reach depth V in the worst case).39

2.3 Undirected Graphs: DFS (Parent Tracking)


Detecting cycles in undirected graphs using DFS is simpler as we don't need three
states. However, we must avoid immediately classifying the edge back to the parent
node as a cycle.
● Mechanism:
Perform a standard DFS. Keep track of the parent node from which the current
node u was reached. When exploring the neighbors v of u, if v is already visited
and v is not the immediate parent of u, then a cycle has been found.1 The check
v!= parent is essential because in an undirected graph, the edge (u, parent)
exists, and traversing it back to the parent is part of the normal DFS process, not
an indication of a cycle.
C++ Implementation:

#include <vector>

// Function to detect cycles in undirected graphs using Depth-First


Search (DFS).
// u: The current vertex being explored.
// parent: The vertex from which u was reached in the DFS traversal.
// visited: A boolean vector indicating whether each vertex has been
visited.
// adj: The adjacency list representing the graph.
// Returns: true if a cycle is detected, false otherwise.
bool detectCycleUndirectedDFS_Util(int u, int parent,
std::vector<bool>& visited, const std::vector<std::vector<int>>& adj)
{
visited[u] = true; // Mark the current vertex as visited.

// Iterate over the neighbors of the current vertex.


for (int v : adj[u]) {
if (!visited[v]) { // If the neighbor has not been visited.
// Recursively invoke DFS on the neighbor.
if (detectCycleUndirectedDFS_Util(v, u, visited, adj)) {
return true; // Cycle detected in the subtree rooted
at the neighbor.
}
} else if (v != parent) { // If the neighbor is visited and is
not the parent.
// A back edge is found, indicating a cycle.
return true; // Cycle detected.
}
// If the neighbor is visited and is the parent, it is the
edge through which the vertex was reached, and should be ignored.
}
return false; // No cycle detected in the traversal from this
vertex.
}

// Function to determine if an undirected graph contains a cycle using


DFS.
// V: The number of vertices in the graph.
// adj: The adjacency list representing the graph.
// Returns: true if a cycle exists in the graph, false otherwise.
bool detectCycleUndirectedDFS(int V, const
std::vector<std::vector<int>>& adj) {
std::vector<bool> visited(V, false); // Initialize an array to
track visited vertices.
// Iterate over all vertices to account for disconnected
components.
for (int i = 0; i < V; ++i) {
if (!visited[i]) {
// Initiate DFS from an unvisited vertex, designating -1
as the initial parent.
if (detectCycleUndirectedDFS_Util(i, -1, visited, adj)) {
return true; // Cycle found.
}
}
}
return false; // No cycle found in the graph.
}

● Complexity Analysis:
○ Time: O(V + E). Standard DFS complexity.40
○ Space: O(V). For the visited array and recursion stack.40

2.4 Undirected Graphs: BFS (Parent Tracking)


BFS can also be adapted for cycle detection in undirected graphs using parent
tracking.
● Mechanism:
Perform a standard BFS using a queue. Store pairs of (node, parent) in the queue
to keep track of how each node was reached. Mark nodes as visited when they
are enqueued. When dequeuing a node u, examine its neighbors v. If a neighbor v
is already visited and v is not the parent of u, a cycle is detected.40
Both BFS and DFS with parent tracking are valid O(V+E) methods for undirected
cycle detection. DFS might be slightly simpler to code recursively. BFS, due to its
level-order nature, tends to find a shortest cycle (in terms of edge count) from
the source node if one exists within that component, whereas DFS does not
guarantee finding the shortest cycle first.51
C++ Implementation:

#include <vector>
#include <queue>
#include <vector>
#include <utility> // For std::pair

// Function to ascertain the presence of a cycle within a single


connected component employing Breadth-First Search (BFS).
// start_node: The initial node for BFS traversal in the component.
// V: The total count of vertices.
// adj: The adjacency list representation of the graph.
// visited: A boolean vector denoting the visitation status of nodes
across components.
// Returns true if a cycle is identified within this component,
otherwise false.
bool detectCycleUndirectedBFS(int start_node, int V, const
std::vector<std::vector<int>>& adj, std::vector<bool>& visited) {
std::queue<std::pair<int, int>> q; // Queue to maintain nodes and
their respective parents.

visited[start_node] = true;
q.push({start_node, -1}); // The start node has no parent,
represented by -1.

while (!q.empty()) {
int u = q.front().first;
int parent = q.front().second;
q.pop();

// Iterate through all neighboring vertices of u.


for (int v : adj[u]) {
if (!visited[v]) { // If neighbor v has not been visited.
visited[v] = true;
q.push({v, u}); // Enqueue neighbor v with u
designated as its parent.
} else if (v != parent) { // If neighbor v has been
visited and is distinct from the parent.
// Cycle detected.
return true;
}
// If neighbor v has been visited and coincides with the
parent, it is disregarded.
}
}
return false; // No cycle was found within this component.
}

// Primary function to determine the existence of a cycle in an


undirected graph using BFS.
// V: The total number of vertices.
// adj: The adjacency list representation of the graph.
bool detectCycleUndirectedBFS_All(int V, const
std::vector<std::vector<int>>& adj) {
std::vector<bool> visited(V, false); // Initialize the visited
array.
// Traverse all vertices to accommodate disconnected graph
components.
for (int i = 0; i < V; ++i) {
if (!visited[i]) {
if (detectCycleUndirectedBFS(i, V, adj, visited)) {
return true; // A cycle has been located within one of
the components.
}
}
}
return false; // No cycle has been discovered in the entire graph.
}

40

● Complexity Analysis:
○ Time: O(V + E). Standard BFS complexity.40
○ Space: O(V). For the visited array and the queue (which can hold up to O(V)
nodes in the worst case).40

2.5 Undirected Graphs: Union-Find


The Union-Find data structure provides an alternative, often efficient way to detect
cycles in undirected graphs, especially when processing edges incrementally.
● Mechanism:
Initialize a DSU structure where each vertex is in its own set. Iterate through the
graph's edges (u, v). For each edge, use the find operation to determine the
representatives (roots) of the sets containing u and v. If the representatives are
the same (find(u) == find(v)), it signifies that u and v are already connected by a
path through previously processed edges. Adding the current edge (u, v) would
create a cycle.29 If the representatives are different, perform the union(u, v)
operation to merge the sets, indicating that u and v (and their respective
components) are now connected by this edge.45 If all edges are processed
without finding two vertices of an edge already in the same set, the graph is
acyclic.
This method works because the DSU structure efficiently tracks the connected
components as edges are added. Finding an edge whose endpoints are already
in the same component implies the existence of an alternative path between
those endpoints within that component. Adding the direct edge closes this
alternative path into a cycle.45
C++ Implementation:

(Requires the DSU class implementation from Section 4.3)

#include <vector>
#include <numeric> // For std::iota
#include <utility> // For std::pair, std::swap

// Assume DSU class from Section 4.3 is defined here...


/*
class DSU {
public:
std::vector<int> parent;
std::vector<int> rank; // Or size

DSU(int n) {... }
int find(int i) {... }
void uniteByRank(int i, int j) {... }
// Or void uniteBySize(int i, int j) {... }
};
*/

// Function to determine if an undirected graph contains a cycle using


the Union-Find algorithm.
// V: The number of vertices in the graph.
// edges: A vector of pairs, where each pair represents an edge {u,
v}.
bool detectCycleUndirectedUF(int V, const std::vector<std::pair<int,
int>>& edges) {
DSU dsu(V); // Initialize the Disjoint Set Union data structure
with V vertices.

// Iterate through each edge of the graph.


for (const auto& edge : edges) {
int u = edge.first;
int v = edge.second;

// Determine the representative elements (roots) of the sets


containing vertices u and v.
int root_u = dsu.find(u);
int root_v = dsu.find(v);

// If vertices u and v belong to the same set, the addition of


this edge would create a cycle.
if (root_u == root_v) {
return true; // A cycle has been detected.
}

// Otherwise, merge the sets containing vertices u and v.


dsu.uniteByRank(u, v); // Or dsu.uniteBySize(u, v);
}

// If no cycle is detected upon processing all edges, the graph is


acyclic.
return false;
}

45

● Complexity Analysis:
○ Time: O(E * α(V)). Initializing the DSU takes O(V). Processing each of the E
edges involves two find operations and potentially one union operation. With
path compression and union by rank/size optimizations, these operations take
O(α(V)) amortized time, where α is the extremely slow-growing inverse
Ackermann function. Thus, the total time is O(V + E * α(V)), which is nearly
linear in E for practical purposes.45
○ Space: O(V). Required to store the parent and rank (or size) arrays for the
DSU structure.45

2.6 Practice Problems (Cycle Detection)


● 207. Course Schedule (Medium): Directed Cycle Detection.1
● 210. Course Schedule II (Medium): Directed Cycle Detection (and Topo Sort).1
● 261. Graph Valid Tree (Medium): Undirected Cycle Detection & Connectivity
Check (BFS/DFS or Union-Find).27
● 684. Redundant Connection (Medium): Undirected Cycle Detection (Union-
Find is highly suitable).27
● 802. Find Eventual Safe States (Medium): Directed Cycle Detection
(identifying nodes not involved in or leading to cycles).27
● 2360. Longest Cycle in a Graph (Hard): Directed Cycle Detection and length
calculation.65
● 2204. Distance to a Cycle in Undirected Graph (Hard): Undirected Cycle
Detection + BFS.66

Table 1: Cycle Detection Method Comparison

Method Graph Type Time Space Notes


Complexity Complexity

DFS (3-State) Directed O(V + E) O(V) Detects back


edges using
GRAY state.
Standard
approach. 27

DFS (Parent Undirected O(V + E) O(V) Detects visited


Tracking) non-parent
neighbors.
Simple recursive
impl. 40

BFS (Parent Undirected O(V + E) O(V) Detects visited


Tracking) non-parent
neighbors. Finds
shortest cycle
first. 40

Union-Find Undirected O(E * α(V)) O(V) Efficient for


incremental
edge
processing (e.g.,
Kruskal's). 45

Kahn's Directed O(V + E) O(V) Detects cycles if


Algorithm (BFS) topological sort
fails (count < V).
15

Section 3: Connectivity
Connectivity explores how vertices are connected within a graph. The concept differs
slightly between undirected and directed graphs.

3.1 Concept
● Undirected Graphs - Connected Components: A connected component is a
maximal subgraph where any two vertices are reachable from each other via
some path. An undirected graph can be partitioned into one or more disjoint
connected components. If a graph has only one connected component, it is
called a connected graph.67
● Directed Graphs - Strongly Connected Components (SCCs): An SCC is a
maximal subgraph where for any two vertices u and v within the subgraph, there
exists a directed path from u to v and a directed path from v to u. Every vertex in
a directed graph belongs to exactly one SCC (which could be a single vertex if it's
not part of a larger strongly connected structure).76
● Condensation Graph: If each SCC in a directed graph G is contracted into a
single "meta-node", the resulting graph of SCCs (with edges representing
connections between components in G) is always a Directed Acyclic Graph
(DAG).27

3.2 Undirected Graphs: Finding Connected Components


The goal is to partition the vertices into sets, where each set represents a connected
component.
● Mechanism:
○ BFS/DFS Approach: This is the standard method for static graphs. Initialize
all nodes as unvisited. Iterate through all nodes. If a node u is unvisited, start
a traversal (either BFS or DFS) from u. All nodes reachable during this
traversal form one connected component. Mark all these reached nodes as
visited. Increment a component counter. Repeat until all nodes are visited.
The final counter value is the number of connected components.67
○ Union-Find Approach: Initialize a DSU structure with each vertex in its own
set. Iterate through all edges (u, v) in the graph. For each edge, perform the
unite(u, v) operation. This merges the sets containing u and v. After
processing all edges, the number of connected components is equal to the
number of disjoint sets remaining in the DSU structure. This can be found by
counting the number of vertices i that are roots of their own set (i.e., find(i)
== i).68
For finding connected components in a static undirected graph, both traversal-
based methods (BFS/DFS) and the Union-Find approach yield the correct result.
BFS and DFS explore components directly from starting nodes, naturally grouping
reachable vertices. Union-Find builds components by merging sets based on
edge connections. While Union-Find offers excellent performance, especially for
dynamic scenarios, the standard O(V+E) complexity and often simpler
implementation of BFS/DFS make them slightly preferred choices for this specific
task on static graphs.71

C++ Implementation (DFS-based):

#include <vector>
#include <numeric> // For std::iota

// Function to perform Depth-First Search (DFS) traversal for


identifying components
void findComponentsDFS_Util(int vertex, std::vector<bool>& visited,
const std::vector<std::vector<int>>& adjacencyList) {
visited[vertex] = true;
// Optionally, add 'vertex' to a list representing the current
component

// Recursively traverse all unvisited adjacent vertices


for (int adjacentVertex : adjacencyList[vertex]) {
if (!visited[adjacentVertex]) {
findComponentsDFS_Util(adjacentVertex, visited,
adjacencyList);
}
}
}

// Function to determine the number of connected components in an


undirected graph
// Parameters:
// V: The number of vertices in the graph
// adjacencyList: Adjacency list representation of the graph
int countConnectedComponents(int V, const
std::vector<std::vector<int>>& adjacencyList) {
std::vector<bool> visited(V, false); // Array to track visited
vertices
int componentCount = 0; // Counter for the number of connected
components

// Iterate over all vertices


for (int i = 0; i < V; ++i) {
// If a vertex has not been visited, it marks the beginning of
a new component
if (!visited[i]) {
findComponentsDFS_Util(i, visited, adjacencyList); //
Apply DFS to identify all vertices within this component
componentCount++; // Increment the count of connected
components
}
}
return componentCount; // Return the total number of connected
components
}

69

● Complexity Analysis:
○ Time: O(V + E) for BFS/DFS using adjacency lists.69 O(V + E * α(V)) for Union-
Find.71
○ Space: O(V) auxiliary space for BFS/DFS (visited array, queue/recursion
stack).69 O(V) for Union-Find (parent/rank arrays).71

3.3 Directed Graphs: Finding Strongly Connected Components (SCCs)


Identifying SCCs requires algorithms that account for the directionality of edges.
Kosaraju's algorithm is a conceptually straightforward method.
● Mechanism (Kosaraju's Algorithm):
Kosaraju's algorithm employs two passes of Depth-First Search (DFS).76
1. First Pass (DFS on Original Graph G): Perform a DFS traversal on the
original graph G. The primary goal of this pass is to compute the "finishing
times" for all vertices. This is achieved by pushing each vertex onto a stack
after all its descendants in the DFS tree have been visited and pushed (i.e.,
when the recursive call for the vertex finishes).76 The vertex that finishes last
will be at the top of the stack.
2. Compute Transpose Graph G_T: Create the transpose (or reverse) graph
G_T by reversing the direction of every edge in the original graph G. If G had
an edge u -> v, then G_T will have an edge v -> u.76 SCCs remain the same in
the transpose graph.76
3. Second Pass (DFS on G_T): Process the vertices in the order they are
popped from the stack obtained in Pass 1 (i.e., in decreasing order of
finishing times). Initialize all vertices as unvisited for this pass. While the stack
is not empty, pop a vertex u. If u has not been visited in this second pass,
start a DFS (or BFS) traversal from u in the transpose graph G_T. All vertices
reachable from u during this traversal in G_T form a single Strongly
Connected Component. Mark all these visited vertices to avoid processing
them again.76 Repeat until the stack is empty. Each time a new DFS is initiated
on an unvisited node from the stack, a new SCC is found.
The intuition behind this process relies on the structure of the condensation
graph (the DAG of SCCs). The first DFS pass effectively orders the SCCs in a
reverse topological order based on finishing times. Processing nodes in this order
during the second DFS on the transpose graph ensures that when we start a DFS
from a node u belonging to an SCC C, the traversal is confined within C. Any edge
leaving C in G_T corresponds to an edge entering C in G. Since we process nodes
from "later" SCCs (in the original graph's condensation DAG) first, any nodes in
"earlier" SCCs that might be reachable in G_T would have already been visited
and assigned to their respective SCCs in previous iterations of the second pass.76

C++ Implementation (Kosaraju's):

#include <vector>
#include <stack>
#include <vector>
#include <algorithm> // For std::fill

// Function: Depth-First Search for the first pass of Kosaraju's


Algorithm on the original graph.
// Parameters:
// u: The starting vertex for DFS traversal.
// adj: The adjacency list representation of the graph.
// visited: A vector of boolean values indicating whether each
vertex has been visited.
// st: A stack to store the vertices in the order of their finishing
times.
void kosarajuDFS1(int u, const std::vector<std::vector<int>>& adj,
std::vector<bool>& visited, std::stack<int>& st) {
visited[u] = true;
for (int v : adj[u]) {
if (!visited[v]) {
kosarajuDFS1(v, adj, visited, st);
}
}
// Push the vertex onto the stack after all reachable vertices
have been visited.
st.push(u);
}

// Function: Depth-First Search for the second pass of Kosaraju's


Algorithm on the transpose graph.
// Parameters:
// u: The starting vertex for DFS traversal.
// adjT: The adjacency list representation of the transpose graph.
// visited: A vector of boolean values indicating whether each
vertex has been visited.
// current_scc: A vector to store the vertices of the currently
identified Strongly Connected Component.
void kosarajuDFS2(int u, const std::vector<std::vector<int>>& adjT,
std::vector<bool>& visited, std::vector<int>& current_scc) {
visited[u] = true;
current_scc.push_back(u); // Add the node to the current Strongly
Connected Component.
for (int v : adjT[u]) {
if (!visited[v]) {
kosarajuDFS2(v, adjT, visited, current_scc);
}
}
}

// Function: Identify all Strongly Connected Components in a graph


using Kosaraju's Algorithm.
// Parameters:
// V: The number of vertices in the graph.
// adj: The adjacency list representation of the original graph.
// Returns:
// A vector of vectors, where each inner vector represents a
Strongly Connected Component.
std::vector<std::vector<int>> findSCCsKosaraju(int V, const
std::vector<std::vector<int>>& adj) {
std::stack<int> st; // Stack to maintain the finishing order of
vertices.
std::vector<bool> visited(V, false);

// Step 1: Populate the stack with vertices sorted by their


finishing times (DFS traversal on the original graph).
for (int i = 0; i < V; ++i) {
if (!visited[i]) {
kosarajuDFS1(i, adj, visited, st);
}
}

// Step 2: Construct the transpose graph (G_T).


std::vector<std::vector<int>> adjT(V);
for (int u = 0; u < V; ++u) {
for (int v : adj[u]) {
adjT[v].push_back(u); // Reverse the edge from u -> v to v
-> u.
}
}

// Step 3: Process vertices in stack order to perform a second DFS


on the transpose graph (G_T).
std::fill(visited.begin(), visited.end(), false); // Reset the
visited array for the second DFS traversal.
std::vector<std::vector<int>> sccs; // Stores the identified
Strongly Connected Components.

while (!st.empty()) {
int u = st.top();
st.pop();

// If the node has not been visited in the second pass,


initiate DFS to discover a Strongly Connected Component.
if (!visited[u]) {
std::vector<int> current_scc; // To accumulate the nodes
of the current Strongly Connected Component.
kosarajuDFS2(u, adjT, visited, current_scc);
sccs.push_back(current_scc); // Add the identified
Strongly Connected Component to the list.
}
}
return sccs;
}

79

● Complexity Analysis (Kosaraju's):


○ Time: O(V + E). The first DFS takes O(V+E). Transposing the graph takes
O(V+E). The second DFS on the transpose graph takes O(V+E). The overall
complexity is linear.79
○ Space: O(V + E). Required for storing the original and transpose adjacency
lists, the visited array, the stack, and the recursion stack depth.79
● Tarjan's Algorithm Mention: An alternative algorithm for finding SCCs is Tarjan's
algorithm. It achieves the same O(V+E) time complexity but requires only a single
DFS pass. It uses concepts of discovery times and "low-link" values to identify
SCCs during the traversal. While potentially more efficient in practice due to
fewer passes, it is generally considered more complex to understand and
implement compared to Kosaraju's algorithm.80
3.4 Practice Problems (Connectivity / SCCs)
● 323. Number of Connected Components in an Undirected Graph (Medium):
Find the number of distinct connected regions in an undirected graph.72
● 547. Number of Provinces (Medium): Similar to 323, but input is an adjacency
matrix.105
● 1192. Critical Connections in a Network (Hard): Find edges (bridges) whose
removal increases the number of connected components. Related to Tarjan's
algorithm for bridges/articulation points.107
● 1489. Find Critical and Pseudo-Critical Edges in Minimum Spanning Tree
(Hard): Involves MST concepts but requires understanding connectivity
changes.108
● 2127. Maximum Employees to Be Invited to a Meeting (Hard): Requires
analyzing cycles and components in a specific type of directed graph.
● 778. Swim in Rising Water (Hard): Find the minimum time (elevation) required to
connect top-left to bottom-right in a grid (connectivity based on threshold).66
● 1334. Find the City With the Smallest Number of Neighbors at a Threshold
Distance (Medium): Involves all-pairs shortest paths and then checking
reachability/connectivity within a distance threshold.66
● 1584. Min Cost to Connect All Points (Medium): An MST problem,
fundamentally about finding the minimum cost way to ensure connectivity.110

Table 2: Connectivity Algorithms Comparison

Task Algorithm Graph Type Time Space Notes


Complexity Complexity

Undirected BFS / DFS Undirected O(V + E) O(V) Standard


Components traversal-
based
approach. 69

Undirected Union-Find Undirected O(V + E * O(V) Efficient,


Components α(V)) good for
dynamic
graphs. 68
Directed Kosaraju's Directed O(V + E) O(V + E) Two DFS
SCCs passes,
conceptually
simpler. 79

Directed Tarjan's Directed O(V + E) O(V) Single DFS


SCCs pass, uses
low-link
values, often
faster. 102

Section 4: Union-Find (Disjoint Set Union - DSU)


The Union-Find (or Disjoint Set Union - DSU) data structure is designed to efficiently
manage a collection of disjoint sets. It excels at two primary operations: determining
which set an element belongs to (find) and merging two sets (union).56

4.1 Concept & Core Operations


● Concept: The core idea is to maintain partitions of a set of elements. Each
element belongs to exactly one set at any given time. Each set is identified by a
unique "representative" or "root" element, which is typically one of the elements
within the set.112
● Representation: A common and efficient way to represent these sets is using a
forest of trees, where each tree corresponds to a set. This forest is usually
implemented using a parent array. parent[i] stores the parent of element i. If
parent[i] == i, then i is the root of its tree and the representative of its set.111
● Core Operations:
○ make_set(i): Initializes element i as a new set containing only itself. Sets
parent[i] = i. If using optimizations, initializes rank to 0 or size to 1.112
Complexity: O(1).
○ find(i): Determines and returns the representative (root) of the set containing
element i. This involves traversing the parent pointers from i upwards until an
element r is found such that parent[r] == r.56 Without optimizations, this can
take O(N) time in the worst case (a degenerate tree resembling a linked list).
○ union(i, j): Merges the two disjoint sets containing elements i and j. It first
finds the representatives of i and j (say, root_i and root_j) using the find
operation. If root_i and root_j are different (meaning i and j are in different
sets), it makes one root the parent of the other, effectively merging the two
trees/sets.56 Without optimizations, the complexity is dominated by the two
find calls, O(N) in the worst case.

4.2 Optimizations
The naive implementation can be very inefficient due to the potential formation of tall,
skinny trees during union operations, leading to linear time complexity for find.112 Two
standard optimizations dramatically improve performance:
● Path Compression: This optimization is applied during the find(i) operation.
After the root r of the set containing i is found, the algorithm retraces the path
from i to r and makes every node on that path point directly to the root r. This
significantly flattens the tree structure, speeding up future find operations for
any node on that path.111 The typical recursive implementation achieves this
concisely: parent[i] = find(parent[i]).111
● Union by Rank / Union by Size: This optimization guides the union(i, j) operation
to keep the trees relatively balanced and shallow.
○ Union by Rank: Each root node maintains a rank, which is an upper bound on
the height of the tree rooted at that node. When uniting two trees with roots
root_i and root_j, the root with the smaller rank is attached as a child to the
root with the larger rank. If the ranks are equal, one is chosen arbitrarily as
the parent, and its rank is incremented by one.112 Path compression can
change the actual height, so rank becomes an upper bound rather than the
exact height.126
○ Union by Size: Each root node maintains the size (number of nodes) of the
tree rooted at that node. When uniting two trees, the root of the smaller tree
(in terms of size) is attached as a child to the root of the larger tree. The size
of the new root is updated by adding the size of the smaller tree.111
Both heuristics, when combined with path compression, yield the same excellent
amortized time complexity.126 Union by size might be preferred if the size of the sets is
needed for other parts of an algorithm.133These two optimizations are highly
complementary. Union by Rank/Size ensures that the underlying tree structure
remains relatively balanced during unions, preventing the worst-case linear height
scenarios. Path Compression then drastically flattens the paths accessed during find
operations, making subsequent accesses along those paths nearly constant time.
While Union by Rank/Size alone guarantees O(log N) per operation, and Path
Compression alone provides an amortized O(log N) bound, it is their combination that
achieves the remarkable near-constant O(α(N)) amortized time complexity.123

4.3 C++ Implementation (with optimizations)


#include <vector>
#include <numeric> // For std::iota
#include <utility> // For std::swap

class DisjointSetUnion {
private:
std::vector<int> parent;
std::vector<int> rank; // Utilizing Union by Rank

public:
// Constructor: Initializes the Disjoint Set Union structure with
n elements, each representing an independent set.
DisjointSetUnion(int n) {
parent.resize(n);
std::iota(parent.begin(), parent.end(), 0); // Initialize each
element as its own parent.
rank.resize(n, 0); // Initialize the rank of each set to 0.
}

// Find operation: Determines the representative element (root) of


the set to which a given element belongs. Implements path compression.
int find(int i) {
if (parent[i] == i)
return i;
return parent[i] = find(parent[i]); // Path compression:
Update parent[i] to point directly to the root.
}

// Unite operation: Merges the sets containing elements i and j.


Implements union by rank.
void unite(int i, int j) {
int root_i = find(i); // Obtain the root of the set containing
i.
int root_j = find(j); // Obtain the root of the set containing
j.
// Proceed only if i and j belong to distinct sets.
if (root_i != root_j) {
// Attach the set with lower rank to the set with higher
rank.
if (rank[root_i] < rank[root_j]) {
parent[root_i] = root_j;
} else if (rank[root_i] > rank[root_j]) {
parent[root_j] = root_i;
} else {
// If ranks are equal, attach one set to the other and
increment the rank of the root.
parent[root_j] = root_i;
rank[root_i]++;
}
}
}

// Check Connectivity: Determines whether two elements belong to


the same set.
bool areConnected(int i, int j) {
return find(i) == find(j);
}
};

// Example Usage:
// DisjointSetUnion dsu(10); // Instantiate a Disjoint Set Union for
10 elements (0-9).
// dsu.unite(1, 2);
// dsu.unite(2, 3);
// bool connectivityStatus = dsu.areConnected(1, 3); // Returns true,
indicating 1 and 3 are in the same set.

111

(Note: An alternative implementation using union by size would replace the rank
vector with a size vector initialized to 1, and the unite logic would compare sizes
instead of ranks, updating the size of the new root accordingly.)

4.4 Complexity Analysis (Amortized)


● Amortized Analysis: This technique analyzes the average cost of operations
over a sequence, allowing for some expensive operations if they make
subsequent operations cheaper. The total cost of a sequence is bounded,
guaranteeing average performance even in the worst-case sequence.112
● Complexity with Optimizations: When using both path compression and union
by rank (or union by size), a sequence of m operations (make_set, find, union) on
n elements takes a total time of O(m * α(n)). Here, α(n) is the inverse
Ackermann function.60
● Inverse Ackermann Function (α(n)): This function grows incredibly slowly. For
any conceivable input size n in practical computing (even vastly exceeding the
number of atoms in the universe), α(n) is less than 5.60
● Effective Complexity: Due to the extremely slow growth of α(n), the amortized
time complexity per operation is considered effectively constant, often written
as O(1) amortized.112

4.5 Applications
The DSU data structure is incredibly useful in algorithms and problems involving
partitioning, connectivity, and equivalence relations:
● Finding Connected Components: Efficiently determines connected
components in undirected graphs, both statically and dynamically (as edges are
added).68
● Cycle Detection in Undirected Graphs: Detects cycles by checking if the
endpoints of an edge already belong to the same set before performing a union.27
● Kruskal's Algorithm for MST: Used to efficiently check if adding the next
cheapest edge would form a cycle by determining if the edge's endpoints are
already in the same component.45
● Network Connectivity: Determining if nodes in a network (computer, social) are
connected.56
● Image Processing: Grouping connected pixels (connected component
labeling).56
● Least Common Ancestor (LCA): Can be used as part of an efficient offline LCA
algorithm.114
● Equivalence Relations: Managing equivalence classes where elements can be
grouped based on transitive relationships.120

4.6 Practice Problems (Union-Find)


● 684. Redundant Connection (Medium): Classic undirected cycle detection.
● 721. Accounts Merge (Medium): Grouping accounts based on shared emails
(equivalence).
● 547. Number of Provinces (Medium): Counting connected components
(adjacency matrix input).105
● 1202. Smallest String With Swaps (Medium): Grouping indices that can be
swapped transitively.
● 947. Most Stones Removed with Same Row or Column (Medium): Connecting
stones, finding components to determine removable stones.
● 261. Graph Valid Tree (Medium): Check connectivity (should be 1 component)
and acyclicity using UF.
● 1101. The Earliest Moment When Everyone Become Friends (Medium):
Process events chronologically, use UF to find the first time all nodes are
connected.105
● 323. Number of Connected Components in an Undirected Graph (Medium):
Direct application of UF for counting components.72
● 990. Satisfiability of Equality Equations (Medium): Group variables based on
'==' constraints, check '!=' constraints against the groups.
● 1319. Number of Operations to Make Network Connected (Medium): Use UF
to find components and determine needed connections.
● 737. Sentence Similarity II (Medium): Group similar words transitively using
UF.105

Section 5: Curated Practice Problems (BFS, DFS, Dijkstra, Union-


Find)
This section provides a curated list of 30 practice problems from LeetCode, focusing
on applying the core graph algorithms covered in this guide: Breadth-First Search
(BFS), Depth-First Search (DFS), Dijkstra's Algorithm, and Union-Find (Disjoint Set
Union). The problems are primarily of Medium and Hard difficulty, designed to solidify
understanding and build problem-solving skills in common graph patterns like grid
traversals, shortest paths, connectivity checks, cycle detection, and state-space
search.

Problem List
The following table lists the problems, categorized by the primary algorithm(s)
typically used for their solution. Note that some problems can be solved using
multiple approaches.
Table 3: Practice Problems List

Problem Title LeetCode ID Focus Difficulty Notes


Algorithm(s)

BFS Focused

Shortest Path in 1091 BFS Medium Grid BFS, 8


Binary Matrix directions 66

01 Matrix 542 BFS Medium Multi-source


BFS from 0s 66

Word Ladder 127 BFS Hard Shortest path in


implicit graph 153

Open the Lock 752 BFS Medium State-space


search

Rotting Oranges 994 BFS Medium Multi-source


BFS, time steps
154

As Far from 1162 BFS Medium Multi-source


Land as BFS from land 66
Possible

Jump Game III 1306 BFS / DFS Medium Graph traversal

Nearest Exit 1926 BFS Medium Grid BFS,


from Entrance in shortest path
Maze

DFS Focused
Number of 200 DFS / BFS / UF Medium Grid
Islands components 153

Clone Graph 133 DFS / BFS Medium Graph traversal,


deep copy 152

Word Search 79 DFS Medium Grid DFS 152


(Backtracking)

Pacific Atlantic 417 DFS / BFS Medium Grid DFS/BFS


Water Flow from boundaries
152

Surrounded 130 DFS / BFS Medium Grid DFS/BFS


Regions from boundaries
77

Max Area of 695 DFS / BFS Medium Grid


Island components,
find max size 77

Flood Fill 733 DFS / BFS Easy Grid traversal 156

Keys and Rooms 841 DFS / BFS Medium Graph traversal,


reachability 157

Dijkstra
Focused

Network Delay 743 Dijkstra / Medium SSSP, non-


Time Bellman-F negative
weights 152

Path with 1514 Dijkstra Medium Maximize


Maximum
Probability (Modified) product path 66

Path With 1631 Dijkstra / UF Medium Dijkstra on grid,


Minimum Effort edge weight =
effort

Number of Ways 1976 Dijkstra + DP Medium SSSP + count


to Arrive at paths
Destination

Minimum 2290 Dijkstra / 0-1 Hard Grid SSSP, 0/1


Obstacle BFS weights 66
Removal to
Reach Corner

Number of 1786 Dijkstra + Medium Dijkstra from


Restricted Paths DP/DFS end, then count
From First to paths 108
Last Node

Reachable 882 Dijkstra Hard Modified


Nodes In Dijkstra on
Subdivided graph
Graph

Union-Find
Focused

Number of 547 Union-Find / Medium Connected


Provinces DFS/BFS components 105

Redundant 684 Union-Find Medium Undirected


Connection cycle detection
27

Accounts Merge 721 Union-Find Medium Grouping


equivalent items

Satisfiability of 990 Union-Find Medium Equivalence


Equality classes
Equations

Smallest String 1202 Union-Find Medium Grouping


With Swaps swappable
indices

Graph Valid 261 Union-Find / Medium Connectivity +


Tree DFS/BFS Acyclicity check
27

Number of 1319 Union-Find Medium Connected


Operations to components
Make Network count
Connected

Mixed / Other

Cheapest 787 Bellman-Ford / Medium SSSP with


Flights Within K Dijkstra constraint (k
Stops (Modified) / BFS stops) 66

This list provides a diverse set of problems covering the algorithms discussed.
Working through these problems will significantly enhance understanding and
proficiency in applying BFS, DFS, Dijkstra's algorithm, and Union-Find to various
graph-related challenges.

This completes the second part of the advanced graph algorithms study guide,
covering Topological Sort, Cycle Detection, Connectivity, Strongly Connected
Components, and the Union-Find data structure. The next parts will delve into
Minimum Spanning Trees and other advanced graph topics.

Works cited
1. Topological Sorting - Algorithms for Competitive Programming, accessed April
14, 2025, https://cp-algorithms.com/graph/topological-sort.html
2. Topological Sort - USACO Guide, accessed April 14, 2025,
https://usaco.guide/gold/toposort
3. Topologically Sorting a Directed Acyclic Graph - Bowdoin College, accessed April
14, 2025,
https://tildesites.bowdoin.edu/~ltoma/teaching/cs231/2021spring/Lectures/L11-
topsort.pdf
4. www.baeldung.com, accessed April 14, 2025, https://www.baeldung.com/cs/dag-
topological-sort#:~:text=In%20many%20applications%2C%20we%20use,a
%20DAG%20to%20represent%20tasks.
5. Understanding the Concept and 2 Applications - Topological Sort, accessed April
14, 2025, https://topological-sort.hashnode.dev/topological-sort-understanding-
the-concept-and-2-applications
6. Topological Sort Using DFS - Tutorial - takeUforward, accessed April 14, 2025,
https://takeuforward.org/data-structure/topological-sort-using-dfs/
7. Topological Sort Algorithm | Interview Cake, accessed April 14, 2025,
https://www.interviewcake.com/concept/java/topological-sort
8. Topological Sort Using DFS, accessed April 14, 2025,
https://blog.heycoach.in/topological-sort-using-dfs/
9. Cycle Detection and Topological Sort Algorithm | Labuladong Algo Notes,
accessed April 14, 2025,
https://labuladong.online/algo/en/data-structure/topological-sort/
10. Introduction to Topological Sort - LeetCode Discuss, accessed April 14, 2025,
https://leetcode.com/discuss/general-discussion/1078072/introduct
11. Topological Sort of Directed Acyclic Graph | Baeldung on Computer ..., accessed
April 14, 2025, https://www.baeldung.com/cs/dag-topological-sort
12. Kahn's Algorithm | Topological Sort Algorithm | BFS: G-22 - Tutorial, accessed
April 14, 2025, https://takeuforward.org/data-structure/kahns-algorithm-
topological-sort-algorithm-bfs-g-22/
13. Kahn's Algorithm for Topological Sorting - Interview kickstart, accessed April 14,
2025, https://interviewkickstart.com/blogs/learn/kahns-algorithm-topological-
sorting
14. Topological Sorting using Kahn's Algorithm - c++ - Stack Overflow, accessed
April 14, 2025, https://stackoverflow.com/questions/70649825/topological-
sorting-using-kahns-algorithm
15. Detect a Cycle in Directed Graph | Topological Sort | Kahn's Algorithm | G-23 -
takeUforward, accessed April 14, 2025, https://takeuforward.org/data-
structure/detect-a-cycle-in-directed-graph-topological-sort-kahns-algorithm-
g-23/
16. GeeksforGeeks-POTD/April 2025 GFG SOLUTION/06(Apr ... - GitHub, accessed
April 14, 2025,
https://github.com/Hunterdii/GeeksforGeeks-POTD/blob/main/April
%202025%20GFG%20SOLUTION/06(Apr)%20Topological%20sort.md
17. Distilled • LeetCode • Topological Sort - aman.ai, accessed April 14, 2025,
https://aman.ai/code/top-sort/
18. Topological Sorting in Graph Using DFS and BFS GeeksForGeeks - DEV
Community, accessed April 14, 2025, https://dev.to/prashantrmishra/topological-
sorting-in-graph-using-dfs-and-bfs-geeksforgeeks-28f2
19. Apply DFS for Topological Sorting of Directed Acyclic Graph in C++ -
Tutorialspoint, accessed April 14, 2025,
https://www.tutorialspoint.com/cplusplus-program-to-apply-dfs-to-perform-
the-topological-sorting-of-a-directed-acyclic-graph
20. Chapter 11 Depth-First Search, accessed April 14, 2025,
https://www.cs.cmu.edu/afs/cs/academic/class/15210-f14/www/lectures/graph-
dfs.pdf
21. 16.4.2 DFS and cycle detection: Topological sorting using DFS, accessed April 14,
2025,
https://courses.grainger.illinois.edu/cs374/fa2020/lec_prerec/16/16_4_2_0.pdf
22. Depth First Search - Algorithms for Competitive Programming, accessed April 14,
2025, https://cp-algorithms.com/graph/depth-first-search.html
23. Why use DFS to find cycles in an undirected graph and topological sorting to find
cycles in a directed graph? - Stack Overflow, accessed April 14, 2025,
https://stackoverflow.com/questions/16779699/why-use-dfs-to-find-cycles-in-
an-undirected-graph-and-topological-sorting-to-fin
24. Topological Sorting | GeeksforGeeks - YouTube, accessed April 14, 2025,
https://m.youtube.com/watch?v=Q9PIxaNGnig
25. Graph For Beginners [Problems | Pattern | Sample Solutions] - LeetCode Discuss,
accessed April 14, 2025,
https://leetcode.com/discuss/study-guide/655708/Graph-For-Beginners-
Problems-or-Pattern-or-Sample-Solutions
26. Topological Sort (w/ DFS) + Course Schedule LeetCode - Reddit, accessed April
14, 2025,
https://www.reddit.com/r/leetcode/comments/dupmul/topological_sort_w_dfs_c
ourse_schedule_leetcode/
27. Checking a graph for acyclicity and finding a cycle in O(M) - Algorithms for
Competitive Programming, accessed April 14, 2025,
https://cp-algorithms.com/graph/finding-cycle.html
28. Cycle detection in Graph: C Program implementation - w3resource, accessed
April 14, 2025, https://www.w3resource.com/c-programming-exercises/graph/c-
graph-exercises-6.php
29. Algorithms for Detecting Cycles in Graphs: A Comprehensive Guide -
AlgoCademy, accessed April 14, 2025, https://algocademy.com/blog/algorithms-
for-detecting-cycles-in-graphs-a-comprehensive-guide/
30. Cycle Detection Using Union-Find, accessed April 14, 2025,
https://blog.heycoach.in/cycle-detection-using-union-find/
31. DETECTING CYCLE IN A GRAPH - Expert Mentoring, Customized ..., accessed
April 14, 2025, https://venkys.io/articles/details/detecting-cycle-in-a-graph
32. Graph theory - Wikipedia, accessed April 14, 2025,
https://en.wikipedia.org/wiki/Graph_theory
33. c++ - Detecting a cycle in a directed graph using DFS? - Stack ..., accessed April
14, 2025, https://stackoverflow.com/questions/31542031/detecting-a-cycle-in-a-
directed-graph-using-dfs
34. Can a 3 Color DFS be used to identify cycles (not just detect them)?, accessed
April 14, 2025, https://cs.stackexchange.com/questions/86148/can-a-3-color-
dfs-be-used-to-identify-cycles-not-just-detect-them
35. How to detect cycles in a directed graph using the iterative version of DFS? -
Stack Overflow, accessed April 14, 2025,
https://stackoverflow.com/questions/46506077/how-to-detect-cycles-in-a-
directed-graph-using-the-iterative-version-of-dfs
36. L06 : Cycle detection in graph using DFS | Graph Theory Part 1 | CodeNCode -
YouTube, accessed April 14, 2025, https://www.youtube.com/watch?
v=SKUOVLqcR9s
37. Detect Cycle in a Directed graph in C++ - YouTube, accessed April 14, 2025,
https://www.youtube.com/watch?v=CFKfmtTwpkw
38. How do you detect if there is a cycle in a graph? : r/C_Programming - Reddit,
accessed April 14, 2025,
https://www.reddit.com/r/C_Programming/comments/1581yts/how_do_you_dete
ct_if_there_is_a_cycle_in_a_graph/
39. G-19. Detect cycle in a directed graph using DFS | Java | C++ - YouTube,
accessed April 14, 2025, https://www.youtube.com/watch?v=9twcmtQj4DU
40. Cycle Detection in an Undirected Graph - TheJat.in, accessed April 14, 2025,
https://thejat.in/code/cycle-detection-in-an-undirected-graph
41. Cycle in an undirected graph using dfs - c++ - Stack Overflow, accessed April 14,
2025, https://stackoverflow.com/questions/49223190/cycle-in-an-undirected-
graph-using-dfs
42. detecting cycles directed graphs vs undirected : r/learnprogramming - Reddit,
accessed April 14, 2025,
https://www.reddit.com/r/learnprogramming/comments/108ldp7/detecting_cycl
es_directed_graphs_vs_undirected/
43. Detect Cycle in an Undirected Graph (using DFS) - Tutorial - takeUforward,
accessed April 14, 2025, https://takeuforward.org/data-structure/detect-cycle-
in-an-undirected-graph-using-dfs/
44. Union-Find Algorithm | Set 1 (Detect Cycle in an Undirected Graph) |
GeeksforGeeks, accessed April 14, 2025, https://www.youtube.com/watch?
v=mHz-mx-8lJ8
45. algorithm - Finding cycles: DFS versus union-find? - Stack Overflow, accessed
April 14, 2025, https://stackoverflow.com/questions/45272145/finding-cycles-
dfs-versus-union-find
46. Finding a cycle and saving its vertices in an undirected, unweighted graph using
BFS, accessed April 14, 2025,
https://stackoverflow.com/questions/69680969/finding-a-cycle-and-saving-its-
vertices-in-an-undirected-unweighted-graph-using
47. 15 Cycle detection In Undirected graph Using BFS - YouTube, accessed April 14,
2025, https://www.youtube.com/watch?v=1ZWTKJpIvpE
48. Detect Cycle in an Undirected Graph (using BFS) - Tutorial, accessed April 14,
2025, https://takeuforward.org/data-structure/detect-cycle-in-an-undirected-
graph-using-bfs/
49. Cycle Detection in Undirected Graph using BFS - YouTube, accessed April 14,
2025, https://www.youtube.com/watch?v=A8ko93TyOns
50. G-11. Detect a Cycle in an Undirected Graph using BFS | C++ | Java - YouTube,
accessed April 14, 2025, https://www.youtube.com/watch?v=BPlrALf1LDU
51. algorithm - Why DFS and not BFS for finding cycle in graphs - Stack ..., accessed
April 14, 2025, https://stackoverflow.com/questions/2869647/why-dfs-and-not-
bfs-for-finding-cycle-in-graphs
52. Disjoint Sets and Cycle Detection : r/computerscience - Reddit, accessed April
14, 2025,
https://www.reddit.com/r/computerscience/comments/p55w4v/disjoint_sets_an
d_cycle_detection/
53. Using Union find to check whether there is a cycle in a graph, accessed April 14,
2025, https://cs.stackexchange.com/questions/105828/using-union-find-to-
check-whether-there-is-a-cycle-in-a-graph
54. Can someone explain intuitively why union find works to find a cycle in an
undirected graph?, accessed April 14, 2025,
https://cs.stackexchange.com/questions/142492/can-someone-explain-
intuitively-why-union-find-works-to-find-a-cycle-in-an-undir
55. Detection of cycle in Graph using find and Union - Stack Overflow, accessed
April 14, 2025, https://stackoverflow.com/questions/43076950/detection-of-
cycle-in-graph-using-find-and-union
56. Union-Find For Cycle Detection, accessed April 14, 2025,
https://blog.heycoach.in/union-find-for-cycle-detection/
57. Kruskal's Algorithm Visually Explained | Disjoint Sets | Union By Rank | Path
Compression, accessed April 14, 2025, https://www.youtube.com/watch?
v=8HeLu8wuLqo
58. Union Find Kruskal's Algorithm - YouTube, accessed April 14, 2025,
https://www.youtube.com/watch?v=JZBQLXgSGfs&pp=0gcJCfcAhR29_xXO
59. Detect cycle in a graph using Kruskal's algorithm - Stack Overflow, accessed
April 14, 2025, https://stackoverflow.com/questions/29998332/detect-cycle-in-a-
graph-using-kruskals-algorithm
60. Does using union-find in Kruskal's algorithm actually affect worst-case runtime?,
accessed April 14, 2025, https://stackoverflow.com/questions/32040718/does-
using-union-find-in-kruskals-algorithm-actually-affect-worst-case-runtime
61. How to detect a cycle in an Undirected Graph using Disjoint Sets? - Stack
Overflow, accessed April 14, 2025,
https://stackoverflow.com/questions/43438419/how-to-detect-a-cycle-in-an-
undirected-graph-using-disjoint-sets
62. Disjoint Set | Union Find | Cycle Detection| Union By Rank | Path Compression -
YouTube, accessed April 14, 2025, https://m.youtube.com/watch?
v=0JE7hxr8c5c&t=0s
63. Union By Rank and Path Compression in Union-Find Algorithm ..., accessed April
14, 2025, https://www.geeksforgeeks.org/union-find-algorithm-set-2-union-by-
rank/
64. Kruskal's Algorithm: Key to Minimum Spanning Tree [MST] - Simplilearn.com,
accessed April 14, 2025, https://www.simplilearn.com/tutorials/data-structure-
tutorial/kruskal-algorithm
65. Longest Cycle in a Graph - LeetCode, accessed April 14, 2025,
https://leetcode.com/problems/longest-cycle-in-a-graph/
66. LeetCode Problems by Official Solution Category - Software Engineering
Handbook, accessed April 14, 2025, https://dwf.dev/docs/learning-resources/lc-
solution-categories
67. BFS and DFS applications - Tyler Moore, accessed April 14, 2025,
https://tylermoore.ens.utulsa.edu/courses/cse3353/slides/l07-handout.pdf
68. Check Vertices in Undirected Graph - Tutorialspoint, accessed April 14, 2025,
https://www.tutorialspoint.com/queries-to-check-if-vertices-x-and-y-are-in-
the-same-connected-component-of-an-undirected-graph
69. Finding Connected Components - Algorithms for Competitive ..., accessed April
14, 2025, https://cp-algorithms.com/graph/search-for-connected-
components.html
70. DFS to find the number of connected components and displaying a cycle -
Reddit, accessed April 14, 2025,
https://www.reddit.com/r/cpp_questions/comments/k95aht/dfs_to_find_the_nu
mber_of_connected_components/
71. Connected Components in an undirected graph - c++ - Stack Overflow,
accessed April 14, 2025,
https://stackoverflow.com/questions/24119528/connected-components-in-an-
undirected-graph
72. 323. Number of Connected Components in an Undirected Graph - In-Depth
Explanation, accessed April 14, 2025, https://algo.monster/liteproblems/323
73. C++ implementation of the algorithm to find number of connected components
in a graph. · Issue #6555 · OpenGenus/cosmos - GitHub, accessed April 14, 2025,
https://github.com/OpenGenus/cosmos/issues/6555
74. Connected Components in a Graph | Baeldung on Computer Science, accessed
April 14, 2025, https://www.baeldung.com/cs/graph-connected-components
75. Number of Connected Components in an Undirected Graph ..., accessed April 14,
2025, https://gkgaurav31.github.io/posts/number-of-connected-components-in-
an-undirected-graph/
76. Strongly Connected Components - USACO Guide, accessed April 14, 2025,
https://usaco.guide/adv/SCC
77. Strongly Connected Components - Neo4j Graph Data Science, accessed April
14, 2025,
https://neo4j.com/docs/graph-data-science/current/algorithms/strongly-
connected-components/
78. CS 161 (Stanford, Winter 2023) Lecture 10 Strongly Connected Components,
accessed April 14, 2025,
https://stanford-cs161.github.io/winter2023/assets/files/lecture10-notes.pdf
79. Strongly Connected Components - Programiz, accessed April 14, 2025,
https://www.programiz.com/dsa/strongly-connected-components
80. Tarjan's Algorithm for Strongly Connected Components - Topcoder, accessed
April 14, 2025, https://www.topcoder.com/thrive/articles/tarjans-algorithm-for-
strongly-connected-components
81. Algorithm for Finding SCC (Strongly Connected Components) in Graphs -
Hypermode, accessed April 14, 2025, https://hypermode.com/blog/algorithm-
for-finding-scc
82. Strongly connected component - Wikipedia, accessed April 14, 2025,
https://en.wikipedia.org/wiki/Strongly_connected_component
83. Kosaraju's Algorithm - Tpoint Tech, accessed April 14, 2025,
https://www.tpointtech.com/kosarajus-algorithm
84. Strongly Connected Components (SCC's), accessed April 14, 2025,
https://tildesites.bowdoin.edu/~ltoma/teaching/cs231/fall14/Lectures/12-SCC/
scc.pdf
85. All Graph Algorithms - One Stop Destination [Standard Implementations] -
LeetCode, accessed April 14, 2025,
https://leetcode.com/discuss/study-guide/6132428/All-Graph-Algorithms-One-
Stop-Destination-Standard-Implementations
86. graph theory - Uses of Strongly Connected Components? - Mathematics Stack
Exchange, accessed April 14, 2025,
https://math.stackexchange.com/questions/32041/uses-of-strongly-connected-
components
87. Difference between a directed cycle and a strongly connected component -
Stack Overflow, accessed April 14, 2025,
https://stackoverflow.com/questions/74413037/difference-between-a-directed-
cycle-and-a-strongly-connected-component
88. c++ - Strongly Connected Components (Kosaraju's Algo) - Stack Overflow,
accessed April 14, 2025, https://stackoverflow.com/questions/78841105/strongly-
connected-components-kosarajus-algo?r=31
89. Kosaraju's algorithm - Wikipedia, accessed April 14, 2025,
https://en.wikipedia.org/wiki/Kosaraju%27s_algorithm
90. Depth First Search Tutorials & Notes | Algorithms - HackerEarth, accessed April
14, 2025, https://www.hackerearth.com/practice/algorithms/graphs/depth-first-
search/tutorial/
91. Union-Find or DFS: which one is better to find connected component? - Stack
Overflow, accessed April 14, 2025,
https://stackoverflow.com/questions/28398101/union-find-or-dfs-which-one-is-
better-to-find-connected-component
92. Strongly Connected Components - Kosaraju's Algorithm: G-54 - Tutorial -
takeUforward, accessed April 14, 2025, https://takeuforward.org/graph/strongly-
connected-components-kosarajus-algorithm-g-54/
93. Algorithms/Graph Algorithms/Kosaraju's Algorithm.cpp at master ·
PetarV-/Algorithms - GitHub, accessed April 14, 2025,
https://github.com/PetarV-/Algorithms/blob/master/Graph%20Algorithms/
Kosaraju's%20Algorithm.cpp
94. Algorithms/Graph algorithms/SCC Kosaraju's algorithm.cpp at master · SH-
anonta/Algorithms - GitHub, accessed April 14, 2025, https://github.com/SH-
anonta/Algorithms/blob/master/Graph%20algorithms/SCC%20Kosaraju's
%20algorithm.cpp
95. Kosaraju's Algorithm Implementation Problem - c++ - Stack Overflow, accessed
April 14, 2025, https://stackoverflow.com/questions/61211219/kosarajus-
algorithm-implementation-problem
96. Strongly Connected Components | GeeksforGeeks, accessed April 14, 2025,
https://www.geeksforgeeks.org/strongly-connected-components/
97. Kosaraju's algorithm's time complexity - Computer Science Stack Exchange,
accessed April 14, 2025,
https://cs.stackexchange.com/questions/39955/kosarajus-algorithms-time-
complexity
98. C++ implementation of tarjan's algorithm for finding Strongly connected
components, accessed April 14, 2025,
https://gist.github.com/APwhitehat/e2ae94b811defc7407bc320f98fd268b
99. Tarjan Algorithms for SCC - graph theory - Stack Overflow, accessed April 14,
2025, https://stackoverflow.com/questions/78654688/tarjan-algorithms-for-scc
100. Tarjan's Algorithm Guide: Upsolving Competitive Programming Challenges,
accessed April 14, 2025, https://blog.garybricks.com/tarjan-algorithm-beginner-
overview
101. Tarjan - Rosetta Code, accessed April 14, 2025,
https://rosettacode.org/wiki/Tarjan
102. Finding Strongly Connected Components: Tarjan's Algorithm | Baeldung on
Computer Science, accessed April 14, 2025, https://www.baeldung.com/cs/scc-
tarjans-algorithm
103. Tarjan's Algorithm: Time Complexity and slight modification possibility - Stack
Overflow, accessed April 14, 2025,
https://stackoverflow.com/questions/24114178/tarjans-algorithm-time-
complexity-and-slight-modification-possibility
104. Tarjan's Strongly Connected Component (SCC) Algorithm (UPDATED) | Graph
Theory, accessed April 14, 2025, https://www.youtube.com/watch?
v=wUgWX0nc4NY&pp=0gcJCfcAhR29_xXO
105. Number of Provinces - LeetCode, accessed April 14, 2025,
https://leetcode.com/problems/number-of-provinces/
106. Number of Connected Components in an Undirected Graph - LeetCode,
accessed April 14, 2025, https://leetcode.com/problems/number-of-connected-
components-in-an-undirected-graph/
107. 1192. Critical Connections in a Network - In-Depth Explanation, accessed April
14, 2025, https://algo.monster/liteproblems/1192
108. List of graph algorithms for coding interview - LeetCode Discuss, accessed April
14, 2025, https://leetcode.com/discuss/general-discussion/753236/list-of-graph-
algorithms-for-coding-interview
109. Find Critical and Pseudo-Critical Edges in Minimum Spanning Tree - LeetCode,
accessed April 14, 2025, https://leetcode.com/problems/find-critical-and-
pseudo-critical-edges-in-minimum-spanning-tree/
110. Min Cost to Connect All Points - LeetCode, accessed April 14, 2025,
https://leetcode.com/problems/min-cost-to-connect-all-points/discuss/
843940/C%2B%2B-MST%3A-Kruskal-%2B-Prim's-%2B-Complete-Graph
111. Disjoint Set Union - USACO Guide, accessed April 14, 2025,
https://usaco.guide/gold/dsu
112. ICS 311 #16: Disjoint Sets and Union-Find - University of Hawaii System,
accessed April 14, 2025,
https://www2.hawaii.edu/~nodari/teaching/s18/Notes/Topic-16.html
113. Disjoint Set Union (Union Find) - HackerEarth, accessed April 14, 2025,
https://www.hackerearth.com/practice/notes/disjoint-set-union-union-find/
114. Disjoint Set Union - Algorithms for Competitive Programming, accessed April 14,
2025, https://cp-algorithms.com/data_structures/disjoint_set_union.html
115. Union-Find (Disjoint Set): A Comprehensive Guide for Efficient Data Structure
Operations, accessed April 14, 2025, https://algocademy.com/blog/union-find-
disjoint-set-a-comprehensive-guide-for-efficient-data-structure-operations/
116. A crash course on Disjoint Set Union (aka Union Find) data structure. - Design
Gurus, accessed April 14, 2025,
https://www.designgurus.io/answers/detail/disjoint-set-union-aka-union-find
117. Union-Find With Union By Rank/Size - Explore Insights, Tips And Articles With
HeyCoach Blogs, accessed April 14, 2025, https://blog.heycoach.in/union-find-
with-union-by-rank-size/
118. Disjoint Set | Union by Rank | Union by Size | Path Compression: G ..., accessed
April 14, 2025, https://takeuforward.org/data-structure/disjoint-set-union-by-
rank-union-by-size-path-compression-g-46/
119. Union-Find Program Debugging : r/Cplusplus - Reddit, accessed April 14, 2025,
https://www.reddit.com/r/Cplusplus/comments/16ld3ex/unionfind_program_deb
ugging/
120. 13.2 Disjoint set data structure and union-find algorithms - Fiveable, accessed
April 14, 2025, https://library.fiveable.me/introduction-algorithms/unit-13/disjoint-
set-data-structure-union-find-algorithms/study-guide/l19GnnC5CX6zvbBo
121. Implementing Disjoint Sets (Union Find) in C++ - Stack Overflow, accessed April
14, 2025, https://stackoverflow.com/questions/4498833/implementing-disjoint-
sets-union-find-in-c
122. Union find, accessed April 14, 2025,
https://courses.cs.washington.edu/courses/cse332/16sp/lectures/Lecture25/25_h
o.pdf
123. Union-Find - cs.Princeton, accessed April 14, 2025,
https://www.cs.princeton.edu/~wayne/kleinberg-tardos/pdf/UnionFind.pdf
124. Complexity/implementation of disjoint-set (union-find) in `DataStructures.jl` -
Julia Discourse, accessed April 14, 2025,
https://discourse.julialang.org/t/complexity-implementation-of-disjoint-set-
union-find-in-datastructures-jl/119050
125. Union by Rank and Path Compression in Union-Find Algorithm - Tutorialspoint,
accessed April 14, 2025, https://www.tutorialspoint.com/union-by-rank-and-
path-compression-in-union-find-algorithm
126. How do path compression and union by rank complement each other? - Stack
Overflow, accessed April 14, 2025,
https://stackoverflow.com/questions/41686826/how-do-path-compression-and-
union-by-rank-complement-each-other
127. Is this Union Find really O(n) as they claim? - Stack Overflow, accessed April 14,
2025, https://stackoverflow.com/questions/71453109/is-this-union-find-really-
on-as-they-claim
128. Union-Find path compression efficiency - algorithm - Stack Overflow, accessed
April 14, 2025, https://stackoverflow.com/questions/47257244/union-find-path-
compression-efficiency
129. Union find - is rank necessary? : r/leetcode - Reddit, accessed April 14, 2025,
https://www.reddit.com/r/leetcode/comments/1e5ayix/union_find_is_rank_neces
sary/
130. Complexity of union-find with path-compression, without rank, accessed April
14, 2025, https://cs.stackexchange.com/questions/48649/complexity-of-union-
find-with-path-compression-without-rank
131. Disjoint set union implementation using c++ - Stack Overflow, accessed April 14,
2025, https://stackoverflow.com/questions/60955485/disjoint-set-union-
implementation-using-c
132. Union Find. Why we don't change rank in find call? - LeetCode Discuss,
accessed April 14, 2025,
https://leetcode.com/discuss/explore/graph/4155748/Union-Find.-Why-we-
don't-change-rank-in-find-call/
133. union by size vs union by rank in disjoint-set algorithm - Stack Overflow,
accessed April 14, 2025, https://stackoverflow.com/questions/65009794/union-
by-size-vs-union-by-rank-in-disjoint-set-algorithm
134. Runtime difference bewteen Union by Rank and Union by Size for union-find,
accessed April 14, 2025,
https://cs.stackexchange.com/questions/128204/runtime-difference-bewteen-
union-by-rank-and-union-by-size-for-union-find
135. Why is the time complexity of performing n union find (union by size) operations
O(n log n)?, accessed April 14, 2025,
https://stackoverflow.com/questions/53149097/why-is-the-time-complexity-of-
performing-n-union-find-union-by-size-operations
136. Amortized analysis and Union-Find, accessed April 14, 2025,
https://www.cs.upc.edu/~mjserna/docencia/grauA/T19/Union-Find.pdf
137. Union-Find and Amortization 1 Introduction - MIT OpenCourseWare, accessed
April 14, 2025, https://ocw.mit.edu/courses/6-046j-design-and-analysis-of-
algorithms-spring-2015/
d25d9d3ba96321326601c8f6dd073e60_MIT6_046JS15_Recitation3.pdf
138. Lecture 1: Amortized Analysis & Union Find - Cheriton School of Computer
Science - University of Waterloo, accessed April 14, 2025,
https://cs.uwaterloo.ca/~r5olivei/courses/2020-fall-cs466/lecture1.pdf
139. Union-Find - Carnegie Mellon University, accessed April 14, 2025,
https://www.cs.cmu.edu/~15451-f23/lectures/lecture06-unionfind.pdf
140. Graph algorithms + problems to practice - LeetCode Discuss, accessed April 14,
2025, https://leetcode.com/discuss/study-guide/1326900/
141. Implement Kruskal's Algorithm in C++ - DEV Community, accessed April 14,
2025, https://dev.to/nokha_debbarma/implement-kruskal-s-algorithm-in-c-29cn
142. Union-Find In Kruskal's Algorithm (MST), accessed April 14, 2025,
https://blog.heycoach.in/union-find-in-kruskals-algorithm-mst/
143. 14.7. Kruskal's Algorithm — CS3 Data Structures & Algorithms - OpenDSA,
accessed April 14, 2025,
https://opendsa-server.cs.vt.edu/ODSA/Books/CS3/html/Kruskal.html
144. Kruskal's Algorithm and Union-Find, accessed April 14, 2025,
https://web.cs.unlv.edu/larmore/Courses/CSC477/S25/Handouts/unionfnd.pdf
145. How to use union-find, minheap, Kruskal's, and a sort algorithm to create a
minimum cost spanning tree? (C++) - Stack Overflow, accessed April 14, 2025,
https://stackoverflow.com/questions/4916287/how-to-use-union-find-minheap-
kruskals-and-a-sort-algorithm-to-create-a-mini
146. Kruskal's Algorithm - Programiz, accessed April 14, 2025,
https://www.programiz.com/dsa/kruskal-algorithm
147. 6.3 Applications of minimum spanning trees - Graph Theory - Fiveable,
accessed April 14, 2025,
https://library.fiveable.me/graph-theory/unit-6/applications-minimum-spanning-
trees/study-guide/iOCen7zmSVC9rHOF
148. Algorithms in Systems Engineering ISE 172 Lecture 22, accessed April 14, 2025,
https://coral.ise.lehigh.edu/~ted/files/ie172/lectures/Lecture22.pdf
149. Union Find Kruskal's Algorithm - YouTube, accessed April 14, 2025,
https://www.youtube.com/watch?v=JZBQLXgSGfs&pp=0gcJCdgAo7VqN5tD
150. Kruskal's Algorithm + Union-Find & MST LeetCode 1584. Min Cost to Connect All
Points, accessed April 14, 2025, https://www.youtube.com/watch?
v=JgmClRWPMX4
151. G-47. Kruskal's Algorithm - Minimum Spanning Tree - C++ and Java - YouTube,
accessed April 14, 2025, https://www.youtube.com/watch?v=DMnDM_sxVig
152. BFS and DFS Graph Problems: Easy to Medium Difficulty - LeetCode Discuss,
accessed April 14, 2025,
https://leetcode.com/discuss/interview-question/5039797/BFS-and-DFS-Graph-
Problems%3A-Easy-to-Medium-Difficulty/
153. Breadth-First Search (BFS) - Shortest Paths in Unweighted Graphs | Interview
Cake, accessed April 14, 2025,
https://www.interviewcake.com/concept/python/bfs?
154. Clone Graph: Ace LeetCode with DFS & BFS - Sean Coughlin's Blog, accessed
April 14, 2025, https://blog.seancoughlin.me/mastering-the-clone-graph-
problem-on-leetcode-a-comprehensive-guide
155. Number of Islands - LeetCode, accessed April 14, 2025,
https://leetcode.com/problems/number-of-islands/
156. Shortest Paths with Unweighted Edges - USACO Guide, accessed April 14, 2025,
https://usaco.guide/gold/unweighted-shortest-paths?lang=java
157. Solving LeetCode Problems Using Graph Theory - HackerNoon, accessed April
14, 2025, https://hackernoon.com/solving-leetcode-problems-using-graph-
theory
158. Graph Algorithms One Place | Dijkstra | Bellman Ford | Floyd Warshall | Prims |
Kruskals | DSU - LeetCode Discuss, accessed April 14, 2025,
https://leetcode.com/discuss/study-guide/969327/Graph-Algorithms-One-
Place-or-Dijkstra-or-Bellman-Ford-or-Floyd-Warshall-or-Prims-or-Kruskals-or-
DSU

You might also like