Debugging challengeIntermediate

DFS that is quadratic for no reason

Scenario

This connected-components counter is textbook DFS, and it returns correct answers. Yet on a graph with 2 · 10^5 vertices and 2 · 10^5 edges it takes 40 seconds and uses gigabytes of memory, while the same algorithm in Python finishes in under a second. Nothing is wrong with the algorithm. Find the bug.

1#include <iostream>
2#include <vector>
3using namespace std;
4
5void dfs(int u, vector<vector<int>> adj, vector<bool> visited) {
6 visited[u] = true;
7 for (int v : adj[u])
8 if (!visited[v]) dfs(v, adj, visited);
9}
10
11int countComponents(int n, vector<vector<int>> adj) {
12 vector<bool> visited(n, false);
13 int components = 0;
14 for (int u = 0; u < n; ++u) {
15 if (!visited[u]) {
16 ++components;
17 dfs(u, adj, visited);
18 }
19 }
20 return components;
21}
22
23int main() {
24 int n = 5;
25 vector<vector<int>> adj(n);
26 auto add = [&](int a, int b) { adj[a].push_back(b); adj[b].push_back(a); };
27 add(0, 1); add(1, 2); add(3, 4);
28 for (auto row : adj) { for (int v : row) cout << v << ' '; cout << '\n'; }
29 cout << countComponents(n, adj) << "\n"; // prints 5, expected 2
30}

Your task

  1. The output is 5, not 2. Explain why every vertex is counted as its own component even though the DFS runs.
  2. Estimate how much data is copied per dfs call, and the total work for V = E = 2 · 10^5.
  3. Fix the signatures. Which parameters should be const&, which &, and why?
  4. There is a third, subtler copy in main. Find it.
  5. State the complexity before and after.
DebuggingOptimizationComplexity Analysis

Work it out

Write your analysis before revealing anything. The self-check below compares it against what a strong answer contains.

Reveal

Progressive — each section builds on the previous one.

The bug
Why it happens
The fix
Edge cases
Complexity

Self-check

Tick what your analysis covered. Be honest — this feeds your readiness profile.

0/6

Related concepts