∑GATE DA Atlas

Graph Traversals and Shortest Paths

Breadth-first and depth-first search in Python with their orders, trees and running times, applications (connected components, cycle detection, bipartiteness, topological sorting), and shortest paths — BFS for unweighted graphs, Dijkstra's algorithm with a heap, Bellman–Ford for negative edges and negative-cycle detection, DAG shortest paths, and Floyd–Warshall for all pairs.

Section 410 practice questions

Breadth-first search (BFS)

Explore the graph layer by layer from a source using a queue.

Python
from collections import deque

def bfs(g, s):
    dist = {s: 0}
    parent = {s: None}
    q = deque([s])
    while q:
        u = q.popleft()
        for v in g[u]:
            if v not in dist:          # first discovery = shortest distance
                dist[v] = dist[u] + 1
                parent[v] = u
                q.append(v)
    return dist, parent
  • Time O(V+E)O(V + E) with adjacency lists (O(V2)O(V^2) with a matrix); space O(V)O(V).
  • Gives shortest paths in unweighted graphs; the parent pointers form a BFS tree.
  • Applications: shortest hops, connected components, bipartiteness (2-colour by BFS layers; an edge inside a layer means an odd cycle), level-order traversal, web crawling, uninformed search in AI (search).

Depth-first search (DFS)

Go as deep as possible, backtracking when stuck. Recursion (or an explicit stack) does the bookkeeping.

Python
def dfs(g, s, seen=None, order=None):
    if seen is None:
        seen, order = set(), []
    seen.add(s)
    order.append(s)                    # pre-order visit
    for v in g[s]:
        if v not in seen:
            dfs(g, v, seen, order)
    return order
  • Time O(V+E)O(V + E); recursion depth up to VV.
  • Record discovery/finish times; in a directed graph edges are tree, back, forward or cross edges. A back edge means a cycle.
  • Applications: connected components, cycle detection, topological sort, strongly connected components, path existence, maze solving, backtracking.
BFS: layers by distance A B C D E F 012 DFS: A B D E F C A B D E F C solid: DFS tree edges · dashed: non-tree edge
Same graph: BFS fans out by distance, DFS dives along one branch.

Topological sorting

A topological order of a DAG lists vertices so every edge goes from earlier to later (task scheduling, build systems, course prerequisites). It exists iff the graph has no directed cycle.

Python
from collections import deque

def topo_sort(g):                           # Kahn's algorithm
    indeg = {u: 0 for u in g}
    for u in g:
        for v in g[u]:
            indeg[v] += 1
    q = deque(u for u in g if indeg[u] == 0)
    order = []
    while q:
        u = q.popleft()
        order.append(u)
        for v in g[u]:
            indeg[v] -= 1
            if indeg[v] == 0:
                q.append(v)
    return order if len(order) == len(g) else None   # None → cycle

Alternative: run DFS and output vertices in reverse finishing order. Both are O(V+E)O(V + E).

Shortest paths in weighted graphs

Relaxation is the shared primitive: if d[u]+w(u,v)<d[v]d[u] + w(u, v) < d[v], set d[v]=d[u]+w(u,v)d[v] = d[u] + w(u, v) and parent[v]=u\text{parent}[v] = u.

Dijkstra's algorithm (non-negative weights)

Python
import heapq

def dijkstra(g, s):                         # g[u] = [(v, w), ...]
    dist = {s: 0}
    pq = [(0, s)]
    done = set()
    while pq:
        d, u = heapq.heappop(pq)
        if u in done:
            continue                        # stale entry
        done.add(u)
        for v, w in g[u]:
            nd = d + w
            if nd < dist.get(v, float("inf")):
                dist[v] = nd
                heapq.heappush(pq, (nd, v))
    return dist
  • Greedy: always finalise the closest unfinished vertex. Correct because with non-negative weights no later path can be shorter.
  • O((V+E)log⁡V)O((V + E)\log V) with a heap; O(V2)O(V^2) with an array.
  • Fails with negative edges (it may finalise a vertex too early).

Bellman–Ford (negative weights allowed)

Relax every edge V−1V - 1 times; a further improvement in round VV reveals a reachable negative cycle. O(VE)O(VE).

Shortest paths in a DAG

Relax edges in topological order: O(V+E)O(V + E), works with negative weights (no cycles to worry about). Negating the weights gives longest paths (critical-path scheduling).

Floyd–Warshall (all pairs)

dk[i][j]=min⁡(dk−1[i][j], dk−1[i][k]+dk−1[k][j])d_k[i][j] = \min(d_{k-1}[i][j],\ d_{k-1}[i][k] + d_{k-1}[k][j]) — allow vertex kk as an intermediate. Three nested loops, O(V3)O(V^3) time, O(V2)O(V^2) space; handles negative edges; a negative d[i][i]d[i][i] means a negative cycle.

Which algorithm?

SituationAlgorithmTime
Unweighted, single sourceBFSO(V+E)O(V + E)
Non-negative weights, single sourceDijkstraO((V+E)log⁡V)O((V + E)\log V)
Negative weights, single sourceBellman–FordO(VE)O(VE)
DAG (any weights)topological-order relaxationO(V+E)O(V + E)
All pairs, denseFloyd–WarshallO(V3)O(V^3)
Weights 0/10-1 BFS with a dequeO(V+E)O(V + E)

Quick revision

Practice questions

GATE-style questions: 3 one-mark and 7 two-mark. Wrong MCQs cost ⅓ of their marks in the real exam; MSQ and NAT have no negative marking. Attempt each before opening the solution.

Q1MCQ2 marks

An undirected graph has adjacency lists (neighbours visited in alphabetical order) A: B, C · B: A, D, E · C: A, F · D: B · E: B, F · F: C, E. The order in which a recursive depth-first search from A visits the vertices is

Q2NAT2 marks

A directed graph has edges with weights S→A 4, S→B 1, B→A 2, A→C 1, B→C 5, C→D 3. The length of the shortest path from S to D is ______.

Q3MCQ1 mark

In an unweighted graph, shortest paths (fewest edges) from a source can be found in O(V+E)O(V + E) time by

Q4MSQ2 marks

Which statements are true?

One or more options are correct.

Q5NAT2 marks

A DAG has vertices 1, 2, 3, 4 and edges 1→21\to2 and 1→31\to3 only. The number of distinct topological orderings is ______.

Q6NAT2 marks

What does this program print?

Python
from collections import deque
g = {0: [1, 2], 1: [3], 2: [3, 4], 3: [5], 4: [5], 5: []}
dist = {0: 0}
q = deque([0])
while q:
    u = q.popleft()
    for v in g[u]:
        if v not in dist:
            dist[v] = dist[u] + 1
            q.append(v)
print(sum(dist.values()))
Q7MCQ1 mark

Dijkstra's algorithm implemented with a binary heap on a graph with VV vertices and EE edges runs in

Q8NAT1 mark

On a graph with 6 vertices and no negative cycles, the Bellman–Ford algorithm needs at most ______ rounds of relaxing every edge to guarantee correct shortest-path distances.

Q9NAT2 marks

What does this program print?

Python
g = {1: [2], 2: [1], 3: [4], 4: [3, 5], 5: [4], 6: []}
seen = set()

def dfs(u):
    seen.add(u)
    for v in g[u]:
        if v not in seen:
            dfs(v)

c = 0
for u in g:
    if u not in seen:
        dfs(u)
        c += 1
print(c)
Q10MCQ2 marks

For the weighted directed graph (S→A 4, S→B 1, B→A 2, A→C 1, B→C 5, C→D 3), the order in which Dijkstra's algorithm extracts (finalises) the vertices is