Graphs model relationships. Cities connected by roads, friends in a social network, dependencies between tasks—all graphs. Mastering graphs means learning to see problems as nodes and edges, then applying the right traversal or algorithm.
Pattern Recognition Signals:
“Connected components” → DFS/BFS + Union-Find
“Shortest path” → BFS (unweighted) or Dijkstra (weighted)
// Unweighted graphint n, m; // n nodes, m edgesvector<vector<int>> adj(n + 1);for (int i = 0; i < m; i++) { int u, v; cin >> u >> v; adj[u].push_back(v); adj[v].push_back(u); // Remove for directed graph}// Weighted graphvector<vector<pair<int, int>>> adj(n + 1); // {neighbor, weight}for (int i = 0; i < m; i++) { int u, v, w; cin >> u >> v >> w; adj[u].push_back({v, w}); adj[v].push_back({u, w});}
vector<vector<int>> adj(n + 1, vector<int>(n + 1, INF));for (int i = 1; i <= n; i++) adj[i][i] = 0;for (int i = 0; i < m; i++) { int u, v, w; cin >> u >> v >> w; adj[u][v] = min(adj[u][v], w);}
DFS explores as deep as possible before backtracking. It’s the foundation for many graph algorithms.
Copy
vector<bool> visited(n + 1, false);void dfs(int u) { visited[u] = true; for (int v : adj[u]) { if (!visited[v]) { dfs(v); } }}// Usagefor (int i = 1; i <= n; i++) { if (!visited[i]) { dfs(i); // Found a new connected component }}
void dfs(int start) { stack<int> st; st.push(start); while (!st.empty()) { int u = st.top(); st.pop(); if (visited[u]) continue; visited[u] = true; for (int v : adj[u]) { if (!visited[v]) { st.push(v); } } }}
Problem: Count connected components or check if two nodes are connected.
Copy
int countComponents(int n, vector<vector<int>>& adj) { vector<bool> visited(n + 1, false); int components = 0; for (int i = 1; i <= n; i++) { if (!visited[i]) { dfs(i); // or bfs(i) components++; } } return components;}
bool hasCycle(int u, int parent) { visited[u] = true; for (int v : adj[u]) { if (!visited[v]) { if (hasCycle(v, u)) return true; } else if (v != parent) { return true; // Back edge found } } return false;}
vector<int> topologicalSort(int n, vector<vector<int>>& adj) { vector<int> inDegree(n + 1, 0); for (int u = 1; u <= n; u++) { for (int v : adj[u]) { inDegree[v]++; } } queue<int> q; for (int i = 1; i <= n; i++) { if (inDegree[i] == 0) q.push(i); } vector<int> order; while (!q.empty()) { int u = q.front(); q.pop(); order.push_back(u); for (int v : adj[u]) { if (--inDegree[v] == 0) { q.push(v); } } } if (order.size() != n) return {}; // Cycle exists return order;}
Problem: Find connected regions in a grid (like paint bucket tool).
Copy
void floodFill(vector<vector<int>>& grid, int r, int c, int newColor) { int oldColor = grid[r][c]; if (oldColor == newColor) return; int n = grid.size(), m = grid[0].size(); queue<pair<int, int>> q; q.push({r, c}); grid[r][c] = newColor; int dx[] = {0, 0, 1, -1}; int dy[] = {1, -1, 0, 0}; while (!q.empty()) { auto [x, y] = q.front(); q.pop(); for (int d = 0; d < 4; d++) { int nx = x + dx[d], ny = y + dy[d]; if (nx >= 0 && nx < n && ny >= 0 && ny < m && grid[nx][ny] == oldColor) { grid[nx][ny] = newColor; q.push({nx, ny}); } } }}