BFS visits vertices in order of distance (in edges) and gives unweighted shortest paths; DFS gives a tree with timestamps whose structure (back edges, subtree intervals, lowlinks) drives cycles, topological order, bridges, SCCs and Euler tours. Both are .

BFS

vector<int> bfs(const vector<vector<int>>& g, const vector<int>& sources) {   // multi-source
    vector<int> d(sz(g), -1); queue<int> q;
    for (int s : sources) if (d[s] < 0) d[s] = 0, q.push(s);
    while (sz(q)) { int u = q.front(); q.pop(); for (int v : g[u]) if (d[v] < 0) d[v] = d[u] + 1, q.push(v); }
    return d;
}

Mark when pushing, not when popping, so each vertex enters the queue once. Keep par[v] = u to recover paths.

Variants:

  • Grids: direction arrays, cell id ; mark walls/visited in place.
  • Multi-source: “distance to the nearest X”; fire spreading. For “escape before the monsters”: BFS from all monsters first, then BFS for the player using only cells reached strictly earlier than the monsters (CSES Monsters).
  • State BFS: vertices , , .
  • Bidirectional BFS: expand the smaller frontier; instead of on puzzle state spaces. Stop when a full layer has been expanded and the frontiers meet; take the minimum over meeting edges.
  • Weights 0/1 or small integers: 0-1 BFS, Dial’s buckets (Shortest Paths).
  • Lexicographically smallest shortest path: BFS from the target for distances, then walk from the source choosing the smallest label among neighbours with distance one less, processing whole layers at once (keep the set of current best vertices).

BFS on the complement graph

The complement of a sparse graph is dense, but BFS on it costs : keep the unvisited vertices in a list; when expanding , every unvisited vertex not adjacent to (in the sparse graph) is visited and removed for good, and every vertex that stays is paid for by an edge of the sparse graph.

vector<int> complementBFS(const vector<vector<int>>& g, int s) {   // g = edges NOT present
    int n = sz(g); vector<int> d(n, -1), mark(n, -1), rest; queue<int> q;
    for (int v = 0; v < n; v++) if (v != s) rest.push_back(v);
    d[s] = 0; q.push(s);
    while (sz(q)) {
        int u = q.front(); q.pop();
        for (int v : g[u]) mark[v] = u;
        vector<int> keep;
        for (int v : rest) if (mark[v] == u) keep.push_back(v); else d[v] = d[u] + 1, q.push(v);
        rest.swap(keep);
    }
    return d;
}

Components of the complement (CF 920E) and MST of a complete graph with 0/1 weights (CF 1242B) use the same loop.

Knight distance on an unbounded board

ll knightDist(ll x, ll y) {                                // offset (x, y), unbounded board
    x = llabs(x), y = llabs(y); if (x < y) swap(x, y);
    if (x == 1 && y == 0) return 3;
    if (x == 2 && y == 2) return 4;
    ll k = max((x + 1) / 2, (x + y + 2) / 3);
    if ((k - x - y) % 2) k++;
    return k;
}

On a bounded board, corners change small distances (corner to its diagonal neighbour needs 4), so BFS there.

DFS and its timestamps

int timer = 0; vector<int> tin, tout, par;
void dfs(int u, int p, const vector<vector<int>>& g) {     // recursion depth = path length: beware 1e6
    tin[u] = timer++; par[u] = p;
    for (int v : g[u]) if (tin[v] < 0) dfs(v, u, g);
    tout[u] = timer++;
}

Iterative DFS that matches recursive order keeps (vertex, next edge index) on an explicit stack.

Edge found when scanning Directed graphUndirected graph
unvisitedtree edgetree edge
on the current path (grey)back edge: cycleback edge: cycle (skip the parent edge by edge id, not vertex, for multigraphs)
finished, forward edgeimpossible
finished, cross edgeimpossible
  • is an ancestor of iff and ; subtrees are contiguous ranges of .
  • Topological order = decreasing (Topological Sort).
  • Lowlinks give bridges, articulation points and SCCs (Bridges, SCC).
  • By itself DFS answers almost nothing; its value is as the skeleton underneath a dozen other algorithms: cycle detection, bipartiteness, topological sort, bridges/articulation points, SCCs, Euler tours, augmenting paths in flows, and maze generation.

Connected components and flood fill

DFS/BFS from each unvisited vertex, or DSU when edges arrive online. In directed graphs this gives weakly connected components; for reachability use SCCs. Number of edges to add to connect everything: . Grid flood fill is the same on the implicit grid graph (label regions, count islands, area of each region — CSES Counting Rooms, Labyrinth, Monsters).

SituationUse
static graph, adjacency list readyDFS/BFS
edges arrive one at a timeDSU
edges are also removeddynamic connectivity
directed graphSCC — plain components are the wrong notion
need bridge-resilience2-edge-connected components
need cut-vertex-resiliencebiconnected components