|
| 1 | +<h1 align='center'>Shortest - Path in - Undirected - Graph</h1> |
| 2 | + |
| 3 | +## Problem Statement |
| 4 | + |
| 5 | +**Problem URL :** [Shortest Path in Undirected Graph](https://www.geeksforgeeks.org/problems/shortest-path-in-undirected-graph-having-unit-distance/1) |
| 6 | + |
| 7 | + |
| 8 | + |
| 9 | + |
| 10 | +## Problem Explanation |
| 11 | +We are given an **undirected graph** with `N` vertices and `M` edges. The graph is represented by a list of edges, where each edge connects two nodes (vertices) in the graph. Our task is to find the **shortest path** from a given source vertex `src` to all other vertices in the graph. The path length is measured by the number of edges traversed. |
| 12 | + |
| 13 | +#### **Example 1:** |
| 14 | +Let's consider an example with 5 vertices (0 to 4) and the following edges: |
| 15 | +``` |
| 16 | +Edges: |
| 17 | +0-1, 0-2, 1-3, 3-4 |
| 18 | +``` |
| 19 | +The graph looks like this: |
| 20 | + |
| 21 | +``` |
| 22 | + 0 -- 1 -- 3 -- 4 |
| 23 | + \ |
| 24 | + 2 |
| 25 | +``` |
| 26 | + |
| 27 | +If the source vertex `src = 0`, the shortest paths from vertex 0 to all other vertices are: |
| 28 | +- `0 → 0` (distance 0) |
| 29 | +- `0 → 1` (distance 1) |
| 30 | +- `0 → 2` (distance 1) |
| 31 | +- `0 → 3` (distance 2) |
| 32 | +- `0 → 4` (distance 3) |
| 33 | + |
| 34 | +The **shortest path** is the one that uses the least number of edges between the source and each target vertex. |
| 35 | + |
| 36 | +#### **Approach:** |
| 37 | +1. **Graph Representation**: We can represent the graph using an adjacency list. Each node will have a list of neighboring nodes it is connected to by an edge. |
| 38 | + |
| 39 | +2. **Breadth-First Search (BFS)**: To find the shortest path in an unweighted graph, we use **BFS**. This is because BFS explores all the nodes at the present depth level before moving on to nodes at the next depth level, guaranteeing the shortest path in an unweighted graph. |
| 40 | + |
| 41 | + - **Why BFS?** BFS explores vertices level by level, ensuring that when we first reach a node, we do so via the shortest possible path. |
| 42 | + |
| 43 | +3. **Steps to Approach**: |
| 44 | + - Initialize a distance array to store the shortest distance from the source to each vertex (set all distances to `-1` initially, except for the source which is set to 0). |
| 45 | + - Use a queue to help with BFS. Add the source node to the queue. |
| 46 | + - While the queue is not empty, process each node: |
| 47 | + - For each unvisited neighboring node, update its distance and mark it as visited, then add it to the queue. |
| 48 | + - Continue this process until all nodes have been visited. |
| 49 | + |
| 50 | + **Key Observations**: |
| 51 | + - BFS ensures that the first time we visit a node, we do so via the shortest path. |
| 52 | + |
| 53 | +#### **Example 2:** |
| 54 | +Consider a graph with 6 vertices and the following edges: |
| 55 | +``` |
| 56 | +Edges: |
| 57 | +0-1, 0-2, 1-3, 3-4, 2-5 |
| 58 | +``` |
| 59 | +``` |
| 60 | + 0 -- 1 -- 3 -- 4 |
| 61 | + \ \ |
| 62 | + 2 -- 5 |
| 63 | +``` |
| 64 | +If the source vertex is `src = 0`, the shortest distances from `0` to all other vertices would be: |
| 65 | +- `0 → 0` (distance 0) |
| 66 | +- `0 → 1` (distance 1) |
| 67 | +- `0 → 2` (distance 1) |
| 68 | +- `0 → 3` (distance 2) |
| 69 | +- `0 → 4` (distance 3) |
| 70 | +- `0 → 5` (distance 3) |
| 71 | + |
| 72 | +## Problem Solution |
| 73 | +```cpp |
| 74 | +class Solution { |
| 75 | + public: |
| 76 | + vector<int> shortestPath(vector<vector<int>>& edges, int N, int M, int src) { |
| 77 | + // Step 1: Create an adjacency list to represent the graph |
| 78 | + vector<vector<int>> adj(N); // Adjacency list with N vertices |
| 79 | + // Build the adjacency list from the given edges |
| 80 | + for (int i = 0; i < M; i++) { |
| 81 | + int u = edges[i][0]; // Start vertex of the edge |
| 82 | + int v = edges[i][1]; // End vertex of the edge |
| 83 | + adj[u].push_back(v); // Add v as a neighbor of u |
| 84 | + adj[v].push_back(u); // Add u as a neighbor of v (since the graph is undirected) |
| 85 | + } |
| 86 | + |
| 87 | + // Step 2: Initialize the distance array and visited array |
| 88 | + vector<int> distance(N, -1); // Distance array, initialized to -1 (unreachable) |
| 89 | + vector<bool> visited(N, false); // Visited array, initialized to false |
| 90 | + queue<int> q; // Queue to store vertices during BFS |
| 91 | + |
| 92 | + // Step 3: Start BFS from the source node |
| 93 | + distance[src] = 0; // Distance to the source is 0 |
| 94 | + visited[src] = true; // Mark the source as visited |
| 95 | + q.push(src); // Add the source node to the queue |
| 96 | + |
| 97 | + // Step 4: Perform BFS to find the shortest path to all nodes |
| 98 | + while (!q.empty()) { |
| 99 | + int node = q.front(); // Get the front node from the queue |
| 100 | + q.pop(); // Remove the front node from the queue |
| 101 | + |
| 102 | + // Step 5: Explore all neighbors of the current node |
| 103 | + for (int neighbor : adj[node]) { |
| 104 | + // If the neighbor hasn't been visited, update its distance and mark it as visited |
| 105 | + if (!visited[neighbor]) { |
| 106 | + visited[neighbor] = true; // Mark the neighbor as visited |
| 107 | + distance[neighbor] = distance[node] + 1; // Update the distance to the neighbor |
| 108 | + q.push(neighbor); // Add the neighbor to the queue for further exploration |
| 109 | + } |
| 110 | + } |
| 111 | + } |
| 112 | + |
| 113 | + // Step 6: Return the final distance array |
| 114 | + return distance; // Return the array containing the shortest distances from src to all vertices |
| 115 | + } |
| 116 | +}; |
| 117 | + |
| 118 | +``` |
| 119 | + |
| 120 | +## Problem Solution Explanation |
| 121 | +Now, let’s break down the given code line by line. |
| 122 | + |
| 123 | +```cpp |
| 124 | +class Solution { |
| 125 | + public: |
| 126 | + vector<int> shortestPath(vector<vector<int>>& edges, int N, int M, int src) { |
| 127 | +``` |
| 128 | +- **Class Definition**: The solution is encapsulated in a class named `Solution`. |
| 129 | +- The method `shortestPath` takes: |
| 130 | + - `edges`: A vector of edges representing the graph. |
| 131 | + - `N`: The number of vertices. |
| 132 | + - `M`: The number of edges. |
| 133 | + - `src`: The source vertex from which we need to calculate the shortest paths to all other vertices. |
| 134 | +
|
| 135 | +```cpp |
| 136 | + vector<vector<int>> adj(N); |
| 137 | +``` |
| 138 | +- **Adjacency List**: An adjacency list `adj` is created to represent the graph. It is a 2D vector where `adj[i]` stores all the nodes connected to vertex `i`. |
| 139 | + |
| 140 | +```cpp |
| 141 | + for (int i = 0; i < M; i++) { |
| 142 | + int u = edges[i][0]; |
| 143 | + int v = edges[i][1]; |
| 144 | + adj[u].push_back(v); |
| 145 | + adj[v].push_back(u); |
| 146 | + } |
| 147 | +``` |
| 148 | +- **Building the Graph**: Loop through each edge. For each edge `(u, v)`, add `v` to `adj[u]` and `u` to `adj[v]`. This creates an undirected graph by adding both directions for each edge. |
| 149 | +
|
| 150 | +```cpp |
| 151 | + vector<int> distance(N, -1); |
| 152 | + vector<bool> visited(N, false); |
| 153 | + queue<int> q; |
| 154 | +``` |
| 155 | +- **Distance Array**: `distance[i]` stores the shortest distance from `src` to vertex `i`. It is initialized to `-1` to signify that no vertex has been visited yet. |
| 156 | +- **Visited Array**: `visited[i]` indicates whether vertex `i` has been visited. It is initially set to `false` for all vertices. |
| 157 | +- **Queue**: A queue `q` is initialized to help with BFS traversal. |
| 158 | + |
| 159 | +```cpp |
| 160 | + distance[src] = 0; |
| 161 | + visited[src] = true; |
| 162 | + q.push(src); |
| 163 | +``` |
| 164 | +- **Initialization**: The distance of the source vertex `src` is set to 0. We mark it as visited and add it to the queue. |
| 165 | + |
| 166 | +```cpp |
| 167 | + while (!q.empty()) { |
| 168 | + int node = q.front(); |
| 169 | + q.pop(); |
| 170 | +``` |
| 171 | +- **BFS Loop**: While the queue is not empty, we process the front node of the queue. |
| 172 | +
|
| 173 | +```cpp |
| 174 | + for (int neighbor : adj[node]) { |
| 175 | + if (!visited[neighbor]) { |
| 176 | + visited[neighbor] = true; |
| 177 | + distance[neighbor] = distance[node] + 1; |
| 178 | + q.push(neighbor); |
| 179 | + } |
| 180 | + } |
| 181 | +``` |
| 182 | +- **Processing Neighbors**: For each unvisited neighbor of the current node: |
| 183 | + - Mark it as visited. |
| 184 | + - Set its distance to the current node's distance + 1. |
| 185 | + - Add the neighbor to the queue. |
| 186 | + |
| 187 | +```cpp |
| 188 | + return distance; |
| 189 | + } |
| 190 | +}; |
| 191 | +``` |
| 192 | +- **Return Result**: After processing all nodes, the `distance` array is returned, which contains the shortest distances from the source to all other vertices. |
| 193 | + |
| 194 | +### **Step 3: Example Walkthrough** |
| 195 | + |
| 196 | +Let’s use the graph from Example 1: |
| 197 | + |
| 198 | +``` |
| 199 | + 0 -- 1 -- 3 -- 4 |
| 200 | + \ |
| 201 | + 2 |
| 202 | +``` |
| 203 | + |
| 204 | +#### Input: |
| 205 | +``` |
| 206 | +edges = {{0, 1}, {0, 2}, {1, 3}, {3, 4}} |
| 207 | +N = 5, M = 4, src = 0 |
| 208 | +``` |
| 209 | + |
| 210 | +1. **Graph Representation**: |
| 211 | + The adjacency list `adj` will look like: |
| 212 | + ``` |
| 213 | + adj = {{1, 2}, {0, 3}, {0}, {1, 4}, {3}} |
| 214 | + ``` |
| 215 | + |
| 216 | +2. **BFS Execution**: |
| 217 | + - `distance = {0, -1, -1, -1, -1}` (initial distances, with `src = 0` set to 0) |
| 218 | + - `visited = {true, false, false, false, false}` (only `src = 0` visited initially) |
| 219 | + - Start BFS: |
| 220 | + - **Process node 0**: Visit neighbors 1 and 2. Update their distances to 1. |
| 221 | + - **Process node 1**: Visit neighbor 3. Update its distance to 2. |
| 222 | + - **Process node 2**: Visit neighbor 5. Update its distance to 3. |
| 223 | + - **Process node 3**: Visit neighbor 4. Update its distance to 3. |
| 224 | + - **Process node 4**: End. |
| 225 | + |
| 226 | +3. **Final Output**: |
| 227 | + ``` |
| 228 | + distance = {0, 1, 1, 2, 3} |
| 229 | + ``` |
| 230 | + |
| 231 | +#### Output: |
| 232 | +``` |
| 233 | +The shortest paths from vertex 0 to all other vertices are: 0 1 1 2 3 |
| 234 | +``` |
| 235 | + |
| 236 | +### **Step 4: Time and Space Complexity** |
| 237 | + |
| 238 | +#### **Time Complexity**: |
| 239 | +- **Graph Construction**: \(O(M)\), where `M` is the number of edges. This is because we process each edge once. |
| 240 | +- **BFS Traversal**: \(O(V + M)\), where `V` is the number of vertices and `M` is the number of edges. We process each vertex and each edge at most once. |
| 241 | +- **Total Time Complexity**: \(O(V + M)\) |
| 242 | + |
| 243 | +#### **Space Complexity**: |
| 244 | +- **Adjacency List**: \(O(V + M)\) space is used for the adjacency list. |
| 245 | +- **Distance Array**: \(O(V)\) |
| 246 | +- **Visited Array**: \(O(V)\) |
| 247 | +- **Queue**: \(O(V)\) in the worst case. |
| 248 | +- **Total Space Complexity**: \(O(V + M)\) |
| 249 | + |
| 250 | +### **Step 5: Additional Recommendations** |
| 251 | +1. **Handling Multiple Components**: If the graph has multiple disconnected components, BFS will only find the shortest path within the component containing the source. If you need to handle disconnected graphs, consider adding extra logic to |
| 252 | + |
| 253 | + mark unreachable nodes or run BFS for each disconnected component. |
| 254 | +2. **Edge Cases**: |
| 255 | + - If there are no edges (`M = 0`), all distances except for the source should remain `-1`. |
| 256 | + - Ensure that `src` is always a valid vertex in the range `[0, N-1]`. |
0 commit comments