Topological Sort & Shortest Paths I

Topological sort, BFS, 0-1 BFS, Dijkstra

Read: ~50 min Advanced 8 practice problems Live code runner

1. Topological Sort — Order Tasks That Depend on Each Other

Given a DAG (directed acyclic graph), produce an order so that for every edge u → v, u comes before v. Used by build systems, course scheduling, package managers, etc.

একটি DAG-এ যদি u → v থাকে, তবে u আগে এবং v পরে আসবে — এই ক্রমকেই topological order বলে। Project build, course prerequisite, package install — সবই topo sort।

2. Kahn's Algorithm — BFS on Indegrees

Compute indegree of every vertex. Push every indegree-0 vertex into a queue. Pop, output, decrement indegrees of neighbours, push any that become 0. If you can't pop V vertices, a cycle exists.

kahn.cpp
#include <bits/stdc++.h>
using namespace std;

int main() {
    int V = 6;
    vector<vector<int>> adj(V);
    vector<int> in(V, 0);
    vector<pair<int,int>> e = {{5,0},{5,2},{4,0},{4,1},{2,3},{3,1}};
    for (auto [u, v] : e) { adj[u].push_back(v); in[v]++; }

    queue<int> q;
    for (int i = 0; i < V; i++) if (in[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 (--in[v] == 0) q.push(v);
    }
    if ((int)order.size() < V) cout << "cycle\n";
    else for (int u : order) cout << u << " ";
}

3. DFS-Based Topo Sort

Run DFS; when a vertex's recursion finishes, push it onto a stack. The reversed stack is a topological order. Quick and natural — but you must guarantee no cycles separately.

Why DFS-finish order works For edge u → v, v finishes before u (DFS calls v first, returns, then u finishes). So in the finish-order list, u comes after v — reverse to get u before v. ∎

4. 0-1 BFS — Deque, Not Priority Queue

When edge weights are only 0 or 1, replace Dijkstra's priority queue with a deque. Push 0-weight successors to the front, 1-weight to the back. Each vertex settles in O(V + E), beating Dijkstra's O(E log V).

যদি edge weight শুধু 0 বা 1 হয়, তবে priority queue-এর বদলে deque যথেষ্ট। 0-edge front-এ, 1-edge back-এ — O(V+E)।

5. Dijkstra — Shortest Path with Non-Negative Weights

Generalises BFS to weighted graphs (no negative edges). Maintain a min-heap of (dist, vertex). Pop the smallest, relax its outgoing edges, push improved successors. Time: O((V + E) log V).

dijkstra.cpp
#include <bits/stdc++.h>
using namespace std;
typedef pair<long long, int> pli;

int main() {
    int V = 5;
    vector<vector<pair<int,int>>> adj(V);   // (neighbour, weight)
    vector<tuple<int,int,int>> e = {{0,1,4},{0,2,1},{2,1,2},{1,3,1},{2,3,5},{3,4,3}};
    for (auto [u, v, w] : e) { adj[u].push_back({v, w}); adj[v].push_back({u, w}); }

    vector<long long> dist(V, LLONG_MAX);
    priority_queue<pli, vector<pli>, greater<>> pq;
    dist[0] = 0; pq.push({0, 0});
    while (!pq.empty()) {
        auto [d, u] = pq.top(); pq.pop();
        if (d > dist[u]) continue;
        for (auto [v, w] : adj[u]) {
            if (dist[u] + w < dist[v]) {
                dist[v] = dist[u] + w;
                pq.push({dist[v], v});
            }
        }
    }
    for (int i = 0; i < V; i++)
        cout << "dist[0..." << i << "] = " << dist[i] << "\n";
}
Dijkstra fails on negative edges Once a vertex is popped, Dijkstra assumes its distance is final. A negative edge could improve it later — breaking the invariant. Use Bellman-Ford (Module 28) for negative weights.

6. Practice Problems

  1. Course Schedule — return any valid order of courses given prerequisite pairs.
    Course Schedule — Kahn's algorithm।
    ✨ Show Answer (উত্তর দেখুন)

    Approach: Kahn's algorithm. If output size < V → cycle → return empty.

  2. Network delay time — using Dijkstra to find max-of-min path from a source.
    Network delay time — Dijkstra।
    ✨ Show Answer (উত্তর দেখুন)

    Approach: Dijkstra from source; answer is max(dist[i]) over all i. If any infinity remains, return -1.

  3. Cheapest flights within K stops — modified Dijkstra / Bellman-Ford-lite.
    K stops-এর মধ্যে সবচেয়ে সস্তা ফ্লাইট।
    ✨ Show Answer (উত্তর দেখুন)

    Approach: BFS-style relaxation for K+1 iterations (Bellman-Ford bounded). Or Dijkstra with state (city, stops_used).

  4. Path with min effort on a grid — binary search + BFS, OR Dijkstra on max-edge-weight metric.
    Min effort path — Dijkstra (max edge weight)।
    ✨ Show Answer (উত্তর দেখুন)

    Approach: Dijkstra where the cost of a path is the maximum edge weight encountered (not the sum). Update dist[v] = max(dist[u], |h[v] − h[u]|).

  5. 0-1 BFS on a grid where 0-cost moves are along free cells and 1-cost moves are crossing walls.
    Grid-এ 0-1 BFS।
    ✨ Show Answer (উত্তর দেখুন)

    Approach: deque BFS; 0-edges push_front, 1-edges push_back. O(V + E).

  6. Longest path in a DAG — modify topo sort.
    DAG-এ longest path।
    ✨ Show Answer (উত্তর দেখুন)

    Approach: compute topological order. Process vertices in that order; for each u, for each edge u→v, do dist[v] = max(dist[v], dist[u] + w(u,v)). O(V+E).

  7. Alien dictionary — given an order over a set of words, derive a valid alphabet order.
    Alien dictionary — char graph + topo sort।
    ✨ Show Answer (উত্তর দেখুন)

    Approach: for each pair of consecutive words, find the first different char and add an edge. Topo-sort the char graph.

  8. Why does Dijkstra need if (d > dist[u]) continue; in the pop step?
    Dijkstra-তে stale pop ignore কেন?
    ✨ Show Answer (উত্তর দেখুন)

    Answer: we may push the same vertex multiple times with different (improving) distances. The first pop is the correct one; later pops carry stale distances and must be skipped, otherwise we would re-relax with worse data.

Summary — Module 27

Topological sort orders DAG vertices so every edge points forward — Kahn's (BFS) or DFS-finish-reverse. BFS gives shortest paths in unweighted graphs. 0-1 BFS uses a deque. Dijkstra with a priority queue solves shortest paths on non-negative graphs in O((V+E) log V). Negative edges? Wait for Bellman-Ford.

BFS — unweighted, deque BFS — 0/1 weight, Dijkstra — non-negative weight। তিনটিই একই backbone, শুধু container আলাদা।

Next Module → Bellman-Ford, Floyd-Warshall, A* — negative edges এবং all-pairs।