Week 8: Graph Algorithms — Routes & Paths
2149 words
11 min read
Visual companion
Python
Type and operator map
Python Week 1: the first filter for runtime behavior
View
Revision summary
What this note is really saying
Short form
# Week 8: Graph Algorithms — Routes & Paths > **BSCS1001 — IIT Madras BS Degree** **Prerequisite:** Week 7 (Graphs, Adjacency Matrices) **Cross-links:** BSCS2002-PDSA (Week 8 — Graph Paths) ## 1. Motivation: Finding Routes Given a train network, how do you find if you can travel from station A to station B?

Week 8: Graph Algorithms — Routes & Paths
BSCS1001 — IIT Madras BS Degree Prerequisite: Week 7 (Graphs, Adjacency Matrices) Cross-links: BSCS2002-PDSA (Week 8 — Graph Paths)
1. Motivation: Finding Routes
Given a train network, how do you find if you can travel from station A to station B?
- Direct route: One train, no changes
- One-hop route: Change trains once (A→X→B)
- Two-hop route: Change trains twice (A→X→Y→B) This is a fundamental graph problem: reachability — which vertices can be reached from which other vertices, and through how many intermediate steps.
Real-world analogy: The "six degrees of separation" — how many introductions do you need to reach any person in the world? That's a multi-hop path in a social network graph.
2. The Train Route Problem
Dataset
Each train has a route: a start station, end station, and (sometimes) intermediate stations.
pseudotrains = { "101": {"start": "Chennai", "end": "Bangalore"}, "102": {"start": "Bangalore", "end": "Mumbai"}, "103": {"start": "Chennai", "end": "Mumbai"}, "104": {"start": "Mumbai", "end": "Delhi"}, "105": {"start": "Bangalore", "end": "Delhi"} }
The Problem
Given this network, answer:
- Can I go from Chennai to Delhi directly? (A direct train?)
- Can I go from Chennai to Delhi with one change? (Chennai→X→Delhi)
- What's the shortest route from Chennai to Delhi? (Diagram)
3. Direct Routes
Algorithm
pseudoProcedure DirectRoutes(trains) // Step 1: Collect all unique stations stations = {} foreach t in keys(trains) { stations[trains[t][start]] = True stations[trains[t][end]] = True } // Step 2: Map stations to indices n = length(keys(stations)) stnindex = {} i = 0 foreach s in keys(stations) { stnindex[s] = i i = i + 1 } // Step 3: Create and populate matrix direct = CreateMatrix(n, n) foreach t in keys(trains) { i = stnindex[trains[t][start]] j = stnindex[trains[t][end]] direct[i][j] = 1 } return(direct) End DirectRoutes
Resulting Matrix
For the 4 stations: Chennai(0), Bangalore(1), Mumbai(2), Delhi(3):
pseudodirect = 0 1 2 3 0 [0, 1, 1, 0] // Chennai → Bangalore, Mumbai 1 [0, 0, 1, 1] // Bangalore → Mumbai, Delhi 2 [0, 0, 0, 1] // Mumbai → Delhi 3 [0, 0, 0, 0] // Delhi → (none)
4. One-Hop Routes
A one-hop route from A to B means: there exists a station K such that:
- A→K is a direct route (direct[A][K] = 1)
- K→B is a direct route (direct[K][B] = 1)
Algorithm
pseudoProcedure WithinOneHop(direct) n = length(keys(direct)) onehop = CreateMatrix(n, n) foreach i in rows(direct) { foreach j in columns(direct) { // First, copy any direct connection onehop[i][j] = direct[i][j] // Check for one-hop connection via intermediate k foreach k in columns(direct) { if (direct[i][k] == 1 AND direct[k][j] == 1) { onehop[i][j] = 1 } } } } return(onehop) End WithinOneHop
How It Works
For each pair (i, j):
- Check every possible intermediate station k
- If i connects to k AND k connects to j, then i can reach j in at most 1 hop
Tracing
Direct matrix:
pseudoC B M D C [0, 1, 1, 0] B [0, 0, 1, 1] M [0, 0, 0, 1] D [0, 0, 0, 0]
Computing onehop:
| i→j | direct? | k candidates | One-hop via k? | onehop[i][j] |
|---|---|---|---|---|
| C→D | 0 (no) | C→B(1), B→D(1) | ✅ B connects | 1 |
| C→M | 1 (yes) | — | — | 1 (direct) |
| C→B | 1 (yes) | — | — | 1 (direct) |
| B→D | 1 (yes) | — | — | 1 (direct) |
| B→? | — | B→M(1), M→D(1) | ✅ via M | B→D already 1 |
| M→? | — | M→D(1), D→? | D→? none | — |
Result (onehop):
pseudoC B M D C [0, 1, 1, 1] // Now Chennai can reach Delhi (via Bangalore or Mumbai) B [0, 0, 1, 1] M [0, 0, 0, 1] D [0, 0, 0, 0]
5. Two-Hop Routes
A two-hop route from A to B means: there exists station K such that:
- A→K is reachable in at most 1 hop (onehop[A][K] = 1)
- K→B is a direct route (direct[K][B] = 1)
Algorithm
pseudoProcedure WithinTwoHops(direct, onehop) n = length(keys(direct)) twohops = CreateMatrix(n, n) foreach i in rows(direct) { foreach j in columns(direct) { // Start with one-hop connections twohops[i][j] = onehop[i][j] // Check for two-hop connection via intermediate k foreach k in columns(direct) { if (onehop[i][k] == 1 AND direct[k][j] == 1) { twohops[i][j] = 1 } } } } return(twohops) End WithinTwoHops
Key Insight
The pattern is: Onemorehop(current, direct) where:
- We start with
current = direct - To go "one more hop," check:
current[i][k] == 1 AND direct[k][j] == 1
6. N-Hop Routes: Generalization
The General Pattern
pseudoProcedure OneMoreHop(current, direct) n = length(keys(direct)) result = CreateMatrix(n, n) foreach i in rows(direct) { foreach j in columns(direct) { result[i][j] = current[i][j] foreach k in columns(direct) { if (current[i][k] == 1 AND direct[k][j] == 1) { result[i][j] = 1 } } } } return(result) End OneMoreHop
Building Up Iteratively
pseudodirect = DirectRoutes(trains) onehop = OneMoreHop(direct, direct) twohops = OneMoreHop(onehop, direct) threehops = OneMoreHop(twohops, direct) // ... and so on
Transitive Closure
The transitive closure of a graph tells us all reachable pairs. We can compute it by repeating
OneMoreHop until no new connections are found:pseudoreachable = direct prev = {} while (reachable ≠ prev) { prev = reachable reachable = OneMoreHop(reachable, direct) }
7. Edge-Labelled Graphs
An edge-labelled graph stores additional information on each edge — such as the train name, distance, or travel time.
Representation
Instead of storing just 0/1, each cell in the matrix stores a dictionary of labels:
pseudo// Create empty dictionaries foreach r in rows(direct) { foreach c in columns(direct) { direct[i][j] = {} // Empty dictionary = no connection } } // Add edges with labels foreach t in keys(trains) { i = stnindex[trains[t][start]] j = stnindex[trains[t][end]] direct[i][j][t] = True // Label with train number }
Result
pseudodirect[Chennai][Bangalore] = {"101": True} // Train 101 connects these direct[Chennai][Mumbai] = {"103": True} // Train 103 connects these
If multiple trains connect the same stations:
pseudodirect[Chennai][Bangalore] = {"101": True, "107": True} // Two trains!
8. Shortest Distance
Problem
Each train has a distance. Find the shortest path between any two stations.
Direct Distances
pseudoProcedure DirectDistance(trains) // ... create station index ... directdist = CreateMatrix(n, n) foreach t in keys(trains) { i = stn2idx[trains[t][start]] j = stn2idx[trains[t][end]] if (directdist[i][j] == 0) { directdist[i][j] = trains[t][distance] } else { // We already have a route — keep the shorter one directdist[i][j] = min(directdist[i][j], trains[t][distance]) } } return(directdist) End DirectDistance
One-Hop Distances
pseudoProcedure OneHopDistance(directdist) n = length(keys(directdist)) onehopdist = CreateMatrix(n, n) foreach i in rows(directdist) { foreach j in columns(directdist) { onehopdist[i][j] = directdist[i][j] foreach k in columns(directdist) { if (directdist[i][k] > 0 AND directdist[k][j] > 0) { newdist = directdist[i][k] + directdist[k][j] if (onehopdist[i][j] > 0) { onehopdist[i][j] = min(newdist, onehopdist[i][j]) } else { onehopdist[i][j] = newdist } } } } } return(onehopdist) End OneHopDistance
This is a simplified version of the Floyd-Warshall algorithm — computing shortest paths between all pairs.
9. Comparison: Route Finding Approaches
| Algorithm | What It Computes | Complexity |
|---|---|---|
| DirectRoutes | All direct connections | O(T) where T = trains |
| OneMoreHop | One additional hop | O(N³) — triple nested loops |
| Transitive Closure | All reachable pairs | O(N³ × K) — repeated until stable |
| Shortest Distance | Minimum path length | O(N³) — similar to Floyd-Warshall |
10. Practice Questions
Basic Questions
Q1. What is a "one-hop route" from station A to station B?
Show AnswerA one-hop route from A to B means there exists an intermediate station K such that:
- There is a direct train from A to K
- There is a direct train from K to B
You can travel A→K→B with one change of train. Q2. In theOneMoreHopprocedure, what does the conditioncurrent[i][k] == 1 AND direct[k][j] == 1check? Show AnswerIt checks whether you can go from i to k using the current reachability matrix, and then from k to j using a direct connection. If both are true, then you can reach j from i with one more hop than before. Q3. What is an edge-labelled graph? Show AnswerAn edge-labelled graph stores additional information on each edge. Instead of just a 0/1 in the matrix, each cell stores a dictionary of labels (e.g., train numbers, distances, travel times). Q4. For the direct matrix of 4 stations, how many cells does the matrix have? How many could potentially be 1? Show AnswerThe matrix is 4×4 = 16 cells. Without self-loops, the diagonal is always 0. So up to 12 cells could be 1 (all possible directed connections between different stations).
Intermediate Questions
Q5. Trace
WithinOneHop for direct matrix:pseudoA B C A [0, 1, 0] B [0, 0, 1] C [0, 0, 0]
Show Answer
| i→j | direct? | k candidates | Via? | onehop[i][j] |
|---|---|---|---|---|
| A→B | 1 | — | — | 1 |
| A→C | 0 | A→B(1), B→C(1) | ✅ via B | 1 (new!) |
| A→A | 0 | A→B(1), B→A(0) → no | none | 0 |
| B→C | 1 | — | — | 1 |
| B→A | 0 | none | none | 0 |
| C→? | 0 | none | none | 0 |
Result:pseudoA B C A [0, 1, 1] // A→C now possible via B B [0, 0, 1] C [0, 0, 0]
Q6. How does
OneMoreHop generalize the process of finding longer paths?Show AnswerOneMoreHop(current, direct)computes connections that are one edge longer than whatcurrentrepresents. By calling it repeatedly:
direct= connections of length 1OneMoreHop(direct, direct)= connections of length ≤ 2OneMoreHop(prev, direct)= connections of length ≤ (prev + 1)This iterative process builds the transitive closure. Q7. In the edge-labelled graph, why do we use a dictionary as the matrix value instead of a list? Show AnswerUsing a dictionary allows O(1) lookup to check if a particular label (train number) exists. A list would require scanning to check membership. The dictionary key is the label, and the value is just True. Q8. Write pseudocode to find all stations reachable from Chennai (station index 0) in at most 2 hops. Show Answersqlreachable = [] foreach j in columns(twohops) { if (twohops[0][j] == 1) { reachable = reachable ++ [j] } } // reachable contains indices of all stations reachable from station 0 in ≤2 hops
Advanced Questions
Q9. How does the shortest distance algorithm differ from the route existence algorithm?
Show AnswerThe route existence algorithm (OneMoreHop) checks if a connection exists (boolean). The shortest distance algorithm checks what the minimum distance is (numeric). Key differences:
- Initialization: Existence uses 0/1; Distance uses 0/positive numbers
- Combination: Existence uses AND; Distance uses addition
- Update: Existence sets to 1; Distance uses
min()to keep shortest- Check: Existence checks
== 1; Distance checks> 0Q10. TraceOneHopDistancefor direct distances:
pseudoA B C A [0, 10, 0] B [0, 0, 20] C [0, 0, 0 ]
Show Answer
| i→j | direct? | via k | newdist | onehopdist[i][j] |
|---|---|---|---|---|
| A→B | 10 | — | — | 10 |
| A→C | 0 | A→B(10), B→C(20) | 10+20=30 | 30 |
| A→A | 0 | none | — | 0 |
| B→C | 20 | — | — | 20 |
| B→A | 0 | none | — | 0 |
| C→? | 0 | none | — | 0 |
Result:A→C = 30(via B) Q11. Explain the relationship between route finding and matrix multiplication. Show AnswerTheOneMoreHopoperation is essentially boolean matrix multiplication:
- Route existence:
result[i][j] = OR over k of (current[i][k] AND direct[k][j])- This is the same as:
result = current × direct(with AND as multiplication, OR as addition)The shortest distance variant is analogous to min-plus matrix multiplication:
result[i][j] = MIN over k of (current[i][k] + direct[k][j])- This is the Floyd-Warshall algorithm.
So route finding is just matrix multiplication in disguise! Q12. Design an algorithm to find if there is a cycle in a directed graph (a path from a station back to itself through other stations). Show AnswerpseudoProcedure HasCycle(direct) n = length(keys(direct)) // Compute transitive closure reachable = direct changed = True while (changed) { changed = False newReachable = OneMoreHop(reachable, direct) if (newReachable ≠ reachable) { changed = True } reachable = newReachable } // Check if any station can reach itself (except self-loop = 0) foreach i in rows(reachable) { if (reachable[i][i] == 1) { return(True) // Cycle exists! } } return(False) End HasCycleA cycle exists if, after computing transitive closure, any diagonal element is 1.
📚 Cross-References
| Course | Topic | Connection |
|---|---|---|
| BSCS2002 (PDSA) | Week 8 — Graph algorithms | Path finding, Floyd-Warshall |
| BSCS2002 (PDSA) | Week 7 — Graph representations | Adjacency matrix |
Next Topic: 15 — RecursionQuiz Tip: One-hop and two-hop routing questions are common in the End Term. Practice the trace pattern! Join Discord PreviousAdjacency MatricesNextRecursion