This deck gives two ways to linearize a DAG - DFS finish-time order, and Kahn's in-degree removal - then shows how strongly connected components are found by Kosaraju's two-pass reverse-graph idea, and why the condensation of any graph's SCCs is always itself a DAG. It targets trying to sort a cyclic graph, the false belief that a topological order is unique, mixing up a directed SCC with an undirected connected component, and forgetting to reverse the graph in Kosaraju's algorithm. Every trace was verified by hand.
Subject: CS3000 Algorithms · 130 slides · symbolic lesson
Open the interactive version of this deck · Homework for this lesson
Title
CS3000 Algorithms
Putting the vertices of a directed graph in a line that respects every arrow — and finding the clumps that can all reach each other.
Objectives
By the end of this lesson you can:
Warm-up
Discussion prompt
Before we open Topological Sort & Strongly Connected Components: without looking back, what was the main idea of Graph Traversal: BFS & DFS, and what could you do by the end of it that you could not do before?
Hint: One sentence for the idea, one for the skill. If the second one is blank, that is the part to revisit.
Answer:
That deck covers breadth-first and depth-first search on graphs stored as adjacency lists. It gives a full BFS trace with a queue and shortest-path parent pointers, explains why BFS finds shortest paths only when every edge costs the same, and gives a full DFS trace with discovery and finish times together with the tree, back, forward, and cross edge classification that DFS reveals. It then explains why both run in time proportional to the number of vertices plus edges rather than to the number of vertices squared. It targets four real misconceptions: trusting BFS shortest paths on weighted graphs, forgetting the visited set, assuming quadratic running time, and mixing up which data structure belongs to which traversal.
Concept
Before any new material: cover the screen.
You have named 14 reusable moves so far. Say as many as you can out loud, by number, from memory.
Do not advance until you have actually tried. Getting four of eight is information; skipping the exercise is not.
Here they are. Score yourself.
Today adds no new moves. Every proof in this lesson is built out of the list above. That is the whole point of the list.
The question that starts every proof from here on is not how do I begin. It is which of these applies here?
Counterexample
Discussion prompt
You have named 14 reusable moves so far. Say as many as you can out loud, by number, from memory.
That is stated as though it always holds. Do one of two things: produce a case where it fails, or say precisely what rules such a case out. "It just does" is not on the menu.
Hint: Hunt at the extremes first — zero, one, negative, empty, equal. If every extreme survives, the reason they survive is the proof.
Answer:
Do not advance until you have actually tried. Getting four of eight is information; skipping the exercise is not.
Section
Section 1
Concept
In a directed graph, an edge points from one vertex to another. Read the edge from A to B as a rule: A must be handled before B.
Stack up enough of these must-come-before rules and you get a whole scheduling problem: which vertex can go first, which has to wait, and is there even a valid way to schedule everyone at all.
Analogy
Discussion prompt
Explain A directed edge means "must come before" by analogy to something with no CS3000 Algorithms in it at all — a queue, a recipe, a map, a bank balance, whatever fits. Then say where your analogy breaks.
Hint: An analogy that never breaks is not an analogy, it is the same idea wearing a hat. Find the seam — that is the part that is actually new.
Answer:
In a directed graph, an edge points from one vertex to another. Read the edge from A to B as a rule: A must be handled before B.
Concept
cycle — A directed path that starts and ends at the same vertex, following edges forward the whole way — for example A to B to C and back to A.
DAG (Directed Acyclic Graph) — A directed graph that contains no cycle at all. Every one of its edges still points somewhere, but you can never follow edges forward and return to where you started.
Definition probe
Sort into buckets
Every line below is part of the definition of cycle or of DAG (Directed Acyclic Graph) — one or the other, never both. Put each where it belongs.
Picture it
Animation
Shows: A cycle makes it impossible — a rendered Manim animation.
Rendered with Manim.
Takeaway: Which is why a back edge is fatal here, not merely interesting.
Intuition
Picture every course you could take as a vertex, and draw an edge from course X to course Y whenever X is a prerequisite for Y. You cannot register for Discrete Math after Algorithms if Algorithms requires Discrete Math first.
A full four-year plan that never breaks a prerequisite rule is exactly a linear ordering of all the courses that respects every arrow. That plan is what we are about to learn to build automatically.
Explain it
Discussion prompt
Explain Think of it as course prerequisites to a student a year behind you. No notation, no jargon they have not met — and it still has to be true.
Hint: If your explanation needs a symbol they have never seen, you are describing the notation rather than the idea.
Answer:
A full four-year plan that never breaks a prerequisite rule is exactly a linear ordering of all the courses that respects every arrow. That plan is what we are about to learn to build automatically.
Concept
A topological ordering lines up every vertex of a graph in a single row so that every directed edge points forward along the row — never backward, never sideways.
If the row is a valid schedule, then for every must-come-before rule in the graph, the earlier vertex really does sit to the left of the later one.
Concept
Written precisely, a topological order is a placement of vertices into positions that satisfies one rule for every single edge in the graph.
\[ \text{For every edge } (u,v):\quad \text{position}(u) < \text{position}(v) \]
Check that rule against every edge and you have either confirmed a valid order, or found the exact edge that breaks it.
Ranking
Put in order
Put the moves of Verify a proposed order by hand into the order they have to happen.
Why: These are the moves of the worked example in the order it makes them, and each one is set up by the one before it. Position tells you where each vertex sits in the row, so you can compare source and target positions for every edge.
Worked example
Here is a small graph and a candidate order to test.
\[ V = \{1,2,3,4\},\quad E = \{(1,2),\,(1,3),\,(2,4),\,(3,4)\} \]
\[ \text{Candidate order: } 1,\ 3,\ 2,\ 4 \]
Assign a position number to each vertex in the candidate order
Why: Position tells you where each vertex sits in the row, so you can compare source and target positions for every edge.
| Vertex | Position |
|---|---|
| 1 | 1 |
| 3 | 2 |
| 2 | 3 |
| 4 | 4 |
Check every edge against the position table
Why: The order is valid only if every single edge has its source at an earlier position than its target — one exception ruins it.
| Edge | Source position | Target position | Source before target? |
|---|---|---|---|
| 1 to 2 | 1 | 3 | yes |
| 1 to 3 | 1 | 2 | yes |
| 2 to 4 | 3 | 4 | yes |
| 3 to 4 | 2 | 4 | yes |
Verify all four edges passed
Why: Every edge in the table came back yes, so 1, 3, 2, 4 is a genuinely valid topological order for this graph — even though it is not the only one, since 2 and 3 have no edge between them.
Concept
This is the theorem the rest of the lesson leans on:
\[ \text{A directed graph has a topological order} \iff \text{it has no cycle.} \]
So before hunting for an order, it is worth asking the simpler question first: does this graph even have one? If it has a cycle, the search is guaranteed to fail.
Picture it
Animation
Shows: A topological order respects every arrow — a rendered Manim animation.
Rendered with Manim.
Takeaway: Any order where every arrow points forwards will do. There is usually more than one.
Concept
Every proof of this kind has the same five or six moves in the same order. The order is not something you rediscover each time.
It is on the right. It will stay on the right through the worked examples that follow.
Why this matters: the structure is now handled. You are not spending working memory on what comes next — you are spending all of it on the one hard step.
Step 3 is the one to slow down on. There is a cycle is useless until you name its vertices and walk them — the contradiction lives in the walk, not in the word cycle.
Intuition
What move should we make next?
The claim:
\[ \text{if } G \text{ has a cycle, no ordering of } V \text{ satisfies every edge} \]
There is nothing here to compute and nothing to trace.
You have a move for exactly this shape of claim. Name it, and say what object you assume into existence.
_Look at your toolkit. Say a move number out loud before this slide advances._ A wrong guess is useful. A silent guess is not.
Intuition
Suppose a cycle existed: X must come before Y, Y must come before Z, and Z must come before X. Try to place all three in a row.
Wherever you put X, the chain eventually demands X come after itself. There is no position for X that satisfies every rule at once — the row itself is impossible, not just hard to find.
Concept
The move: #7 (Negate and assume), then #8 (Take the extreme one).
Negate and assume: suppose a valid ordering exists
Why: Assume a topological order exists on a graph that also has a cycle. Now you have two named objects to collide.
Take the extreme one: the earliest cycle vertex in that order
Why: Do not reason about a generic cycle vertex. Take the one that appears first in the ordering, and call it v.
Walk the cycle and read the contradiction
Why: The cycle contains an edge into v from some other cycle vertex u. A valid ordering puts u before v — but v was chosen to be earliest. Collision.
\[ u \to v \;\Rightarrow\; u \text{ before } v, \qquad v \text{ earliest} \;\Rightarrow\; v \text{ before } u \]
The extremal choice is doing all the work again. A generic cycle vertex gives you nothing to violate; the earliest one has a property that the edge into it destroys.
Notation
Annotate
From The move we just made, named — read this one piece at a time. What is each part doing?
On: \( u \to v \;\Rightarrow\; u \text{ before } v, \qquad v \text{ earliest} \;\Rightarrow\; v \text{ before } u \)
Picture it
Figure (svg): A six-vertex graph A through F with a normal forward chain of edges, plus one added edge from F back to A, creating a cycle through A, C, and F.
Discussion prompt
Read the picture before the words. What is this showing, and what is the one thing it is built to make obvious? Commit to an answer, then read on.
Hint: Name the parts, then say what changes between them — and if nothing changes, say what is being held still.
Answer:
A student takes a six-vertex graph, adds one extra edge from F back to A, and then just lists the vertices in their usual order anyway.
Trap
A student takes a six-vertex graph, adds one extra edge from F back to A, and then just lists the vertices in their usual order anyway.
Figure (svg): A six-vertex graph A through F with a normal forward chain of edges, plus one added edge from F back to A, creating a cycle through A, C, and F.
List A, B, C, D, E, F and call it done
Why: This order was valid before the extra edge was added, so the student assumes it still works. But the new edge from F to A demands F come before A, and this order puts F last and A first — the exact opposite.
Check for a cycle before trusting any order. Compute in-degrees first.
\[ \text{in-degree}(A) = 1 \text{ (now fed by F)}, \text{ every other vertex keeps its old in-degree} \]
Look for a starting vertex with in-degree 0
Why: Every vertex now has at least one incoming edge, since A gained one from F while nothing lost its old incoming edges. There is nowhere for an ordering to legally begin.
\[ \text{No vertex has in-degree } 0 \implies \text{the graph has a cycle} \implies \text{no topological order exists} \]
Section
Section 2
Concept
discovery time — The moment a depth-first search first visits a vertex and starts exploring from it.
finish time — The moment a depth-first search is completely done with a vertex — every vertex reachable from it by an unvisited path has already been fully explored.
A single shared clock ticks forward every time any vertex is discovered or finished, so every vertex ends up with two distinct timestamps.
Picture it
Animation
Shows: DFS finish times give it for free — a rendered Manim animation.
Rendered with Manim.
Takeaway: The last thing to finish has nothing depending on it, so it goes first.
Concept
Run one depth-first search over the whole graph, recording a finish time for every vertex. Then list the vertices from the largest finish time down to the smallest.
That single sort — nothing fancier — turns out to be a valid topological order, as long as the graph has no cycle.
Intuition
Whenever vertex A has an edge to vertex B, depth-first search cannot fully finish with A until it has completely explored everything reachable from A — and B is reachable from A.
So B always finishes before A does. A vertex that finishes later has already "waited out" everything it points to, which is exactly what a must-come-before rule needs — the source finishing last means it belongs earlier in the row.
Intuition
What feels wrong about this?
The rule is: run DFS, then list vertices in decreasing finish time.
Finish time is when a vertex is done — the last thing that happens to it. It is being used to decide what goes first.
_Plain English only. No notation, no algebra. Just say what bothers you._
The feeling: it feels backwards. The thing that finishes last is put at the front of the list.
That feeling is the proof. It is not a substitute for the proof — it is the thing the proof writes down.
But finishing late is exactly the signal you want: a vertex finishes only after everything reachable from it has finished. So a late finish means lots of things depend on being after me, which is precisely what belongs at the front.
Concept
For every edge in a DAG, the source vertex always finishes strictly after the target vertex.
\[ (u,v) \in E \implies f(u) > f(v) \]
Sort by decreasing finish time and this lemma guarantees u lands to the left of v for every single edge — precisely the topological order requirement.
Picture it
Figure (svg): A six-vertex directed acyclic graph: A points to B and C; B points to D; C points to D and F; D points to E; E points to F.
Discussion prompt
Read the picture before the words. What is this showing, and what is the one thing it is built to make obvious? Commit to an answer, then read on.
Hint: Name the parts, then say what changes between them — and if nothing changes, say what is being held still.
Answer:
Here is the graph we will trace all lesson: six vertices, seven edges.
Worked example
Here is the graph we will trace all lesson: six vertices, seven edges.
\[ V=\{A,B,C,D,E,F\},\ E=\{(A,B),(A,C),(B,D),(C,D),(D,E),(C,F),(E,F)\} \]
Figure (svg): A six-vertex directed acyclic graph: A points to B and C; B points to D; C points to D and F; D points to E; E points to F.
Run DFS from A, visiting neighbors in alphabetical order
Why: Starting at A and always choosing the alphabetically first unvisited neighbor gives one fixed, repeatable trace: A leads to B leads to D leads to E leads to F, then back up to try C.
\[ A \to B \to D \to E \to F \ (\text{dead end, backtrack all the way to } A) \to C \]
Record discovery and finish times as the search backtracks
Why: F has nowhere new to go, so it finishes immediately; then E, then D, then B all finish in turn as the recursion unwinds. C is visited last from A, finds both its neighbors already finished, and finishes right away.
| Vertex | Discovery time | Finish time |
|---|---|---|
| A | 1 | 12 |
| B | 2 | 9 |
| C | 10 | 11 |
| D | 3 | 8 |
| E | 4 | 7 |
| F | 5 | 6 |
Sort the vertices by decreasing finish time
Why: Ranking the finish times 12, 11, 9, 8, 7, 6 from largest to smallest lines up A, C, B, D, E, F.
\[ \text{Order: } A,\ C,\ B,\ D,\ E,\ F \]
Verify the order against every edge
Why: Assign positions A=1, C=2, B=3, D=4, E=5, F=6, then check each edge keeps its source at an earlier position than its target.
| Edge | Source position | Target position | Valid? |
|---|---|---|---|
| A to B | 1 | 3 | yes |
| A to C | 1 | 2 | yes |
| B to D | 3 | 4 | yes |
| C to D | 2 | 4 | yes |
| D to E | 4 | 5 | yes |
| C to F | 2 | 6 | yes |
| E to F | 5 | 6 | yes |
Pattern
Step through it
Step through Full DFS trace: finish-time order on a six-vertex DAG one row at a time. What is driving the change, and what would the row after the last one be?
Anomaly
Predict first
A student writes this, and it looks reasonable:
Reusing the same DFS trace, a student sorts by increasing discovery time instead, since that also looks like a natural order.
It is wrong. Say what breaks — and say it before you turn the page.
Correct: This puts C dead last, since C was not discovered until time 10 — but check the edge from C to D.
Discovery time only records when a vertex was first reached — it says nothing about whether everything below it is done yet. Finish time does.
Why: This puts C dead last, since C was not discovered until time 10 — but check the edge from C to D. D sits at position 3 while C sits at position 6, so C comes after D, which directly violates the edge C to D.
Trap
Reusing the same DFS trace, a student sorts by increasing discovery time instead, since that also looks like a natural order.
\[ \text{Discovery times: } A{=}1, B{=}2, D{=}3, E{=}4, F{=}5, C{=}10 \]
List A, B, D, E, F, C in order of increasing discovery time
Why: This puts C dead last, since C was not discovered until time 10 — but check the edge from C to D. D sits at position 3 while C sits at position 6, so C comes after D, which directly violates the edge C to D.
Discovery time only records when a vertex was first reached — it says nothing about whether everything below it is done yet. Finish time does.
\[ \text{Rule: sort by DECREASING finish time, never discovery time} \]
Use finish times instead: 12, 11, 9, 8, 7, 6
Why: That produces A, C, B, D, E, F, which we already verified against every edge, including C to D (positions 2 and 4 — valid).
Step zero
Discussion prompt
A second finish-time trace, for practice — before any calculation: what is the plan? Name the moves in order, in plain English, without doing the arithmetic.
Hint: It starts with: Run DFS from P, visiting Q before R
Answer:
Worked example
A small diamond-shaped graph: one task branches into two, which both feed into a final task.
\[ V=\{P,Q,R,S\},\ E=\{(P,Q),(P,R),(Q,S),(R,S)\} \]
Run DFS from P, visiting Q before R
Why: P discovers Q first; Q leads straight to S, which has no unvisited neighbors and finishes immediately, so Q finishes right after. Back at P, R is visited next, finds S already finished, and finishes immediately too.
| Vertex | Discovery time | Finish time |
|---|---|---|
| P | 1 | 8 |
| Q | 2 | 5 |
| R | 6 | 7 |
| S | 3 | 4 |
Sort by decreasing finish time
Why: Ranking 8, 7, 5, 4 from largest to smallest gives P, R, Q, S — note this places R before Q, even though Q was visited first.
\[ \text{Order: } P,\ R,\ Q,\ S \]
Verify the order against every edge
Why: Positions: P=1, R=2, Q=3, S=4. Edge P to Q: 1 before 3, valid. Edge P to R: 1 before 2, valid. Edge Q to S: 3 before 4, valid. Edge R to S: 2 before 4, valid. All four edges hold.
Picture it
Animation
Shows: Each line of the worked example "A second finish-time trace, for practice", appearing one at a time.
The same working the example does, in the order a tutor would write it.
Takeaway: Positions: P=1, R=2, Q=3, S=4. Edge P to Q: 1 before 3, valid. Edge P to R: 1 before 2, valid. Edge Q to S: 3 before 4, valid. Edge R to S: 2 before 4, valid. All four edges hold.
Section
Section 3
Concept
in-degree — The number of edges pointing INTO a vertex — how many other vertices must come before this one.
A vertex with in-degree of exactly zero has nothing standing in its way. Every one of its prerequisites, if it has any at all, is already satisfied — trivially, because it has none.
Matching
Match the pairs
Match each term to the definition this lesson gave it — not the one you would guess from the word.
Why: These are the working definitions of cycle, DAG (Directed Acyclic Graph), discovery time, finish time, in-degree as Topological Sort & Strongly Connected Components uses them. Pairing them correctly is the test of whether you could state each one with the slide switched off.
Estimation
Predict first
Using the same six-vertex graph, count how many arrows point into each vertex.
Commit before you compute: what does Compute the in-degree of every vertex come out to? A rough magnitude and the right form is enough — the point is to have something concrete to be wrong about.
Correct: Verify the in-degrees against the edge count
Why: A prediction you can defend turns the computation into a check rather than a leap of faith — and an answer that contradicts it is caught on the spot. Every edge contributes exactly one incoming arrow somewhere, so the in-degrees must add up to the total number of edges: 0 + 1 + 1 + 2 + 1 + 2 = 7, which matches the seven edges listed above.
Worked example
Using the same six-vertex graph, count how many arrows point into each vertex.
\[ E=\{(A,B),(A,C),(B,D),(C,D),(D,E),(C,F),(E,F)\} \]
Count incoming edges for each vertex
Why: A has no edges pointing into it at all. B and C each receive one edge, from A. D receives two, from B and C. E receives one, from D. F receives two, from C and E.
| Vertex | Incoming edges | In-degree |
|---|---|---|
| A | (none) | 0 |
| B | A to B | 1 |
| C | A to C | 1 |
| D | B to D, C to D | 2 |
| E | D to E | 1 |
| F | C to F, E to F | 2 |
Verify the in-degrees against the edge count
Why: Every edge contributes exactly one incoming arrow somewhere, so the in-degrees must add up to the total number of edges: 0 + 1 + 1 + 2 + 1 + 2 = 7, which matches the seven edges listed above.
Pattern
Step through it
Step through Compute the in-degree of every vertex one row at a time. What is driving the change, and what would the row after the last one be?
Concept
Kahn's algorithm builds the order one vertex at a time: repeatedly find a vertex with in-degree zero, place it next, and remove it from the graph.
Removing a vertex also removes its outgoing edges, which lowers the in-degree of whatever it pointed to — possibly freeing up brand new vertices to be picked next.
Sorting
Sort into buckets
These are the pieces of Topological Sort & Strongly Connected Components, out of order. Put each one back under the part of the lesson it belongs to.
Intuition
Think of every vertex as a task waiting on a certain number of other tasks to finish first. A task with nothing left waiting on it can be done right now.
Do it, cross it off, and check whether any task that was depending on it now has nothing left in its way either. Keep clearing the front of the line until nothing is left.
Concept
Start a queue with every vertex whose in-degree is currently zero
Why: These are the only legal starting points, since nothing stands in front of them.
Repeat: remove one vertex from the queue, append it to the order, and decrease the in-degree of each of its neighbors by one
Why: Removing a finished vertex means its outgoing edges no longer count against anyone.
Whenever a neighbor's in-degree drops to zero, add it to the queue
Why: That neighbor's remaining prerequisites are now all satisfied, so it becomes legal to place next.
Concept
Count how many prerequisites each task has, then repeatedly take anything with none left. The counter is the whole algorithm.
KAHN(G)
for each u in V
indeg[u] = number of edges into u
R = every u with indeg[u] == 0
order = empty list
while R is not empty
u = remove any vertex from R
append u to order
for each v in Adj[u]
indeg[v] = indeg[v] - 1
if indeg[v] == 0
add v to R
if order.length < V.length
report a cycle
return orderLine 10 does not delete an edge; it just decrements a count, which has the same effect and costs nothing. Line 13 is the cycle test: vertices trapped in a cycle keep each other's counts above zero forever, so they never reach R.
Notation
Every line of KAHN says one thing. Read the line, then read what it does — not the other way round.
Annotate
Invariant
Every vertex already in order has had all its prerequisites placed before it. That is exactly the definition of a topological order, maintained at every step rather than checked at the end.
Step through it
At each step, name every vertex currently ready, and notice when there is more than one.
Picture it
Animation
Shows: KAHN executing: the current line of pseudocode is highlighted while the data it touches changes.
Rendered with Manim.
Takeaway: Repeatedly take a vertex with no remaining prerequisites; if the order comes out short, the graph had a cycle.
Concept
A vertex is only ever placed in the order once every one of its prerequisites has already been placed — that is exactly what dropping its in-degree to zero means.
\[ \text{running time: } \Theta(|V| + |E|) \]
Every vertex enters and leaves the queue exactly once, and every edge is examined exactly once when its source is removed, so the whole algorithm is proportional to the size of the graph.
Picture it
Animation
Shows: Usually there is more than one valid order — a rendered Manim animation.
Rendered with Manim.
Takeaway: Which is why your answer and the book's can differ and both be right.
Ranking
Put in order
Put the moves of Full trace: Kahn's algorithm on the six-vertex graph into the order they have to happen.
Why: These are the moves of the worked example in the order it makes them, and each one is set up by the one before it. Removing A drops the in-degree of both B and C by one, since A pointed to each of them.
Worked example
Starting in-degrees, from the previous computation: A=0, B=1, C=1, D=2, E=1, F=2.
Only A has in-degree zero, so remove it first
Why: Removing A drops the in-degree of both B and C by one, since A pointed to each of them.
| Step | Vertex removed | In-degree updates | Ready to remove next |
|---|---|---|---|
| 0 | (none yet) | (none yet) | A |
| 1 | A | B: 1 to 0, C: 1 to 0 | B, C |
| 2 | B | D: 2 to 1 | C |
| 3 | C | D: 1 to 0, F: 2 to 1 | D |
| 4 | D | E: 1 to 0 | E |
| 5 | E | F: 1 to 0 | F |
| 6 | F | (none) | (none left) |
Read off the order the vertices were removed in
Why: The removal order IS the topological order Kahn's algorithm produces.
\[ \text{Order: } A,\ B,\ C,\ D,\ E,\ F \]
Verify the order against every edge
Why: Positions A=1, B=2, C=3, D=4, E=5, F=6. Every edge listed (A-B, A-C, B-D, C-D, D-E, C-F, E-F) has its source at a strictly smaller position than its target.
Picture it
Animation
Shows: Each line of the worked example "Full trace: Kahn's algorithm on the six-vertex graph", appearing one at a time.
The same working the example does, in the order a tutor would write it.
Takeaway: Positions A=1, B=2, C=3, D=4, E=5, F=6. Every edge listed (A-B, A-C, B-D, C-D, D-E, C-F, E-F) has its source at a strictly smaller position than its target.
Intuition
If the queue ever runs dry while vertices still remain unplaced, none of the leftover vertices currently has in-degree zero.
That can only happen if every remaining vertex is still waiting on some other remaining vertex — which is exactly what a cycle among them looks like. No amount of waiting will ever free one of them up.
Ranking
Put in order
Put the moves of Kahn's algorithm detects a cycle into the order they have to happen.
Why: These are the moves of the worked example in the order it makes them, and each one is set up by the one before it. Only A's in-degree changes, since the new edge points into A; F's in-degree is unaffected, since in-degree counts edges pointing IN, not out.
Worked example
Take the same graph and add one edge from F back to A, exactly as in the earlier trap.
\[ \text{Extra edge: } (F,A) \]
Recompute every in-degree
Why: Only A's in-degree changes, since the new edge points into A; F's in-degree is unaffected, since in-degree counts edges pointing IN, not out.
| Vertex | In-degree |
|---|---|
| A | 1 |
| B | 1 |
| C | 1 |
| D | 2 |
| E | 1 |
| F | 2 |
Try to start the queue
Why: Every single vertex now has an in-degree of at least one. There is no vertex to place first, so the queue starts completely empty.
Verify by counting processed vertices against the total
Why: The algorithm halts having placed zero of the six vertices. Since zero does not equal six, some vertices were never freed up — confirming the graph contains a cycle and has no topological order.
Picture it
Animation
Shows: Each line of the worked example "Kahn's algorithm detects a cycle", appearing one at a time.
The same working the example does, in the order a tutor would write it.
Takeaway: The algorithm halts having placed zero of the six vertices. Since zero does not equal six, some vertices were never freed up — confirming the graph contains a cycle and has no topological order.
Anomaly
Predict first
A student writes this, and it looks reasonable:
A student computes the DFS finish-time order on the six-vertex graph, gets A, C, B, D, E, F, and then marks Kahn's algorithm's answer of A, B, C, D, E, F as wrong because it disagrees.
It is wrong. Say what breaks — and say it before you turn the page.
Correct: This assumes a graph has exactly one valid topological order, so two different results must mean a mistake was made somewhere.
Check BOTH orders against every edge instead of assuming only one can be right.
Why: This assumes a graph has exactly one valid topological order, so two different results must mean a mistake was made somewhere.
Trap
A student computes the DFS finish-time order on the six-vertex graph, gets A, C, B, D, E, F, and then marks Kahn's algorithm's answer of A, B, C, D, E, F as wrong because it disagrees.
\[ \text{DFS order: } A,C,B,D,E,F \quad\text{vs.}\quad \text{Kahn's order: } A,B,C,D,E,F \]
Declare one of the two answers incorrect
Why: This assumes a graph has exactly one valid topological order, so two different results must mean a mistake was made somewhere.
Check BOTH orders against every edge instead of assuming only one can be right.
\[ \text{Both orders satisfy every edge in } E=\{(A,B),(A,C),(B,D),(C,D),(D,E),(C,F),(E,F)\} \]
Notice there is no edge between B and C at all
Why: Since neither vertex requires the other to come first, their relative order is free to swap — which is exactly the difference between the two results.
Translation
\( \text{DFS order: } A,C,B,D,E,F \quad\text{vs.}\quad \text{Kahn's order: } A,B,C,D,E,F \)
Draw it
Translate both ways. First write the expression above as a sentence with no symbols in it at all. Then cover it, and write your sentence back as notation. If the two versions disagree, the disagreement is the thing to fix.
Section
Section 4
Concept
reachable — Vertex v is reachable from vertex u if there is some directed path from u to v, following one or more edges forward — not necessarily a single direct edge.
\[ u \rightsquigarrow v \quad \text{means "} v \text{ is reachable from } u\text{"} \]
Concept
A strongly connected component (SCC) is a maximal group of vertices where every vertex can reach every other vertex in the group, going forward along directed edges, in both directions.
\[ u \text{ and } v \text{ are in the same SCC} \iff u \rightsquigarrow v \ \text{ and } \ v \rightsquigarrow u \]
Maximal means the group cannot be grown any further: no outside vertex can be added while keeping every pair mutually reachable.
Picture it
Animation
Shows: A strongly connected component — a rendered Manim animation.
Rendered with Manim.
Takeaway: Every vertex in the cycle reaches every other. The fourth vertex is not in it.
Intuition
Picture a group of friends who can each visit any other friend's house and make it back home, using only one-way streets. That whole group is one strongly connected component.
Someone who can visit the group's houses but can never get back once they leave is not part of the clump, no matter how close their house is. Reachability has to go both ways.
Concept
An ordinary connected component, from an undirected graph, only asks whether SOME path connects two vertices, ignoring direction entirely.
A strongly connected component is a stricter, directed notion: it asks for a path back AND a path forth, both following arrows the correct way. Erasing the arrows and asking the undirected question is a completely different computation.
Picture it
Figure (svg): A triangle of vertices G, H, I with edges forming a cycle G to H to I to G, plus one extra edge from I out to J with no edge returning.
Discussion prompt
Read the picture before the words. What is this showing, and what is the one thing it is built to make obvious? Commit to an answer, then read on.
Hint: Name the parts, then say what changes between them — and if nothing changes, say what is being held still.
Answer:
Consider this graph and the claim that G, H, and I form one strongly connected component, with J entirely separate.
Worked example
Consider this graph and the claim that G, H, and I form one strongly connected component, with J entirely separate.
\[ E=\{(G,H),(H,I),(I,G),(I,J)\} \]
Figure (svg): A triangle of vertices G, H, I with edges forming a cycle G to H to I to G, plus one extra edge from I out to J with no edge returning.
Check mutual reachability for every pair inside the claimed group
Why: Each pair needs a path in both directions, using only the edges given.
| Pair | Path one way | Path the other way | Mutually reachable? |
|---|---|---|---|
| G and H | G to H (direct) | H to I to G | yes |
| H and I | H to I (direct) | I to G to H | yes |
| G and I | G to H to I | I to G (direct) | yes |
Check whether J belongs in the group too
Why: J is reachable FROM I, but J has no outgoing edge at all, so J cannot reach I, H, or G. Mutual reachability fails, so J cannot be merged in.
| Pair | Path one way | Path the other way | Mutually reachable? |
|---|---|---|---|
| I and J | I to J (direct) | no path exists from J back | no |
Verify no other vertex can be merged in
Why: G, H, and I reach each other every possible way, and J cannot complete the loop back. So the SCCs are exactly {G, H, I} and {J}, matching the claim.
Comparison
Comparison matrix
From Verify a candidate group really is one SCC: refill the Mutually reachable? column from what you know. The rest of the table is as it appeared.
| Pair | Path one way | Path the other way | Mutually reachable? |
|---|---|---|---|
| G and H | G to H (direct) | H to I to G | yes |
| H and I | H to I (direct) | I to G to H | yes |
| G and I | G to H to I | I to G (direct) | yes |
Picture it
Figure (svg): Three vertices X, Y, Z in a straight line with a directed edge from X to Y and another from Y to Z, and no edges going backward.
Discussion prompt
Read the picture before the words. What is this showing, and what is the one thing it is built to make obvious? Commit to an answer, then read on.
Hint: Name the parts, then say what changes between them — and if nothing changes, say what is being held still.
Answer:
A student sees a simple chain, X points to Y and Y points to Z, and declares all three vertices one strongly connected component, since you can get from X all the way to Z by following the arrows.
Trap
A student sees a simple chain, X points to Y and Y points to Z, and declares all three vertices one strongly connected component, since you can get from X all the way to Z by following the arrows.
\[ E = \{(X,Y),(Y,Z)\} \]
Figure (svg): Three vertices X, Y, Z in a straight line with a directed edge from X to Y and another from Y to Z, and no edges going backward.
Group X, Y, Z as one SCC because a path connects them
Why: This only checks reachability in ONE direction, treating the graph as if it were undirected. It never asks whether Y or Z can get back to X.
Test mutual reachability strictly, using only the directed edges as given.
\[ X \rightsquigarrow Y \ (\text{yes}), \quad Y \rightsquigarrow X \ (\text{no path exists}) \]
Conclude each vertex is its own singleton SCC
Why: No vertex here can reach backward at all, so none of the three pairs is mutually reachable. As an undirected graph, ignoring direction, all three would form one connected component — but that is a different question with a different answer.
Break the constraint
Discussion prompt
The rule this trap just fixed:
Test mutual reachability strictly, using only the directed edges as given.
Now break it on purpose. Build a case that violates it and follow the consequences until something visibly fails. Where does the failure first show up — and would you have noticed it if you had not been looking?
Hint: The dangerous rules are the ones whose violation still produces an answer. If yours fails loudly, try to find one that fails quietly.
Answer:
This only checks reachability in ONE direction, treating the graph as if it were undirected. It never asks whether Y or Z can get back to X.
Concept
Kosaraju's algorithm finds every strongly connected component in two passes. Pass one: run a plain DFS over the whole graph and record a finish time for every vertex, exactly as in the topological sort method.
Nothing about SCCs is decided yet in pass one — it only produces the same kind of finish-time ranking used earlier for topological sort.
Concept
Pass two runs DFS again, but on the REVERSE of the graph, and processes vertices in decreasing order of the finish times from pass one.
Every separate tree that this second DFS builds is exactly one strongly connected component — nothing more needs to be checked afterward.
Concept
reverse graph — The same set of vertices, with every edge flipped: an edge from u to v in the original graph becomes an edge from v to u in the reverse graph.
\[ (u,v) \in E \implies (v,u) \in E^{R} \]
Every path that existed in the original graph now runs backward in the reverse graph, and vice versa. Nothing about which vertices exist changes — only which direction each arrow points.
Intuition
Watch me not know the answer. This is what the first two minutes actually look like.
Kosaraju runs DFS once on the graph and once on the reverse. The reversal step feels like an extra complication.
Try running the second pass on the original graph, in decreasing finish order
Why: It removes the reversal step and the code gets simpler. Worth thirty seconds to see what it produces.
The second pass swallows everything downstream
Why: Starting from the highest-finish vertex, DFS on the original graph reaches every vertex that vertex can reach — which includes whole components downstream of it. You get one giant blob, not the components.
Dead end. Not a mistake — a move that was worth trying and did not pay off. This happens in most proofs.
Back up. Reversing is what confines the search
Why: In the reverse graph, DFS from v reaches exactly the vertices that can reach v in the original. Intersecting v reaches them with they reach v is the definition of an SCC, and the two passes supply one half each.
The reversal is not an implementation trick. It is the second half of the definition. Trying the simpler version is what makes that visible.
The expert does not see the whole path in advance. The expert tries something, reads the result, and adjusts. That is the skill.
Intuition
The vertex with the highest finish time from pass one sits in a component that has no incoming edges from any other component — call it a source component of the whole graph's clump structure.
Flip every edge and that source component gains no way OUT to any other component either, since its only cross-component edges used to point in, and now they point back in the other direction. Starting the second DFS there, on the reverse graph, can only wander inside that one component — it has nowhere else to escape to.
Picture it
Animation
Shows: Why reversing the edges is the trick — a rendered Manim animation.
Rendered with Manim.
Takeaway: So the second pass cannot leak out of the component it starts in.
Picture it
Figure (svg): Eight vertices in three clusters: 1, 2, 3 form a triangle cycle; 4, 5, 6 form a triangle cycle; 7 and 8 point to each other; the clusters are chained together by an edge from 3 to 4 and an edge from 6 to 7.
Discussion prompt
Read the picture before the words. What is this showing, and what is the one thing it is built to make obvious? Commit to an answer, then read on.
Hint: Name the parts, then say what changes between them — and if nothing changes, say what is being held still.
Answer:
This graph has three built-in cycles: one among 1, 2, 3; one among 4, 5, 6; and one between 7 and 8.
Worked example
This graph has three built-in cycles: one among 1, 2, 3; one among 4, 5, 6; and one between 7 and 8.
\[ E=\{(1,2),(2,3),(3,1),(3,4),(4,5),(5,6),(6,4),(6,7),(7,8),(8,7)\} \]
Figure (svg): Eight vertices in three clusters: 1, 2, 3 form a triangle cycle; 4, 5, 6 form a triangle cycle; 7 and 8 point to each other; the clusters are chained together by an edge from 3 to 4 and an edge from 6 to 7.
Run DFS from vertex 1, always following the lowest-numbered unvisited neighbor
Why: 1 leads to 2, to 3, to 4, to 5, to 6, to 7, to 8 — one long chain, since each vertex's only unvisited neighbor at that point is the next one in the chain.
\[ 1 \to 2 \to 3 \to 4 \to 5 \to 6 \to 7 \to 8 \]
Record finish times as the recursion unwinds from 8 back to 1
Why: 8 has nowhere new to go (7 is already on the stack) and finishes first; then 7, 6, 5, 4, 3, 2, and finally 1 all finish in turn as the search backtracks all the way home.
| Vertex | Discovery time | Finish time |
|---|---|---|
| 1 | 1 | 16 |
| 2 | 2 | 15 |
| 3 | 3 | 14 |
| 4 | 4 | 13 |
| 5 | 5 | 12 |
| 6 | 6 | 11 |
| 7 | 7 | 10 |
| 8 | 8 | 9 |
Verify every vertex received a finish time
Why: All eight vertices show a finish time between 9 and 16 with no repeats, confirming the DFS visited and completely finished every vertex exactly once.
Pattern
Step through it
Step through Kosaraju pass one: DFS finish times on an eight-vertex graph one row at a time. What is driving the change, and what would the row after the last one be?
Picture it
Figure (svg): The same eight vertices with every edge reversed: the two triangle cycles now run the opposite way around, the 7 and 8 pair is unchanged, and the two connecting edges now point from cluster 4-5-6 back to cluster 1-2-3, and from cluster 7-8 back to cluster 4-5-6.
Discussion prompt
Read the picture before the words. What is this showing, and what is the one thing it is built to make obvious? Commit to an answer, then read on.
Hint: Name the parts, then say what changes between them — and if nothing changes, say what is being held still.
Answer:
Flip every edge from the previous graph to build the reverse graph.
Worked example
Flip every edge from the previous graph to build the reverse graph.
\[ E^{R}=\{(2,1),(3,2),(1,3),(4,3),(5,4),(6,5),(4,6),(7,6),(8,7),(7,8)\} \]
Figure (svg): The same eight vertices with every edge reversed: the two triangle cycles now run the opposite way around, the 7 and 8 pair is unchanged, and the two connecting edges now point from cluster 4-5-6 back to cluster 1-2-3, and from cluster 7-8 back to cluster 4-5-6.
Process vertices in decreasing finish-time order from pass one: 1, 2, 3, 4, 5, 6, 7, 8
Why: Vertex 1 has the highest finish time (16), so it starts the first tree of pass two.
| Vertex tried | Already visited? | Action |
|---|---|---|
| 1 | no | start Tree 1: DFS on reverse graph visits 1, then 3, then 2 |
| 2 | yes | already in Tree 1, skip |
| 3 | yes | already in Tree 1, skip |
| 4 | no | start Tree 2: DFS on reverse graph visits 4, then 6, then 5 |
| 5 | yes | already in Tree 2, skip |
| 6 | yes | already in Tree 2, skip |
| 7 | no | start Tree 3: DFS on reverse graph visits 7, then 8 |
| 8 | yes | already in Tree 3, skip |
Read off the three trees as the three SCCs
Why: Tree 1 covers vertices 1, 2, 3; Tree 2 covers 4, 5, 6; Tree 3 covers 7 and 8. Each tree from this reverse-graph pass is exactly one strongly connected component.
\[ \text{SCCs: } \{1,2,3\},\ \{4,5,6\},\ \{7,8\} \]
Verify each group is mutually reachable and no two groups should merge
Why: Inside {1,2,3}, the cycle 1 to 2 to 3 to 1 makes every pair mutually reachable; the same holds for {4,5,6} and for {7,8}. Across groups, only 3 to 4 and 6 to 7 connect them, both one-way, so no vertex in a later group can ever reach back into an earlier one — the three groups cannot be merged.
Comparison
Comparison matrix
From Kosaraju pass two: DFS on the reverse graph: refill the Action column from what you know. The rest of the table is as it appeared.
| Vertex tried | Already visited? | Action |
|---|---|---|
| 1 | no | start Tree 1: DFS on reverse graph visits 1, then 3, then 2 |
| 2 | yes | already in Tree 1, skip |
| 3 | yes | already in Tree 1, skip |
| 4 | no | start Tree 2: DFS on reverse graph visits 4, then 6, then 5 |
| 5 | yes | already in Tree 2, skip |
| 6 | yes | already in Tree 2, skip |
| 7 | no | start Tree 3: DFS on reverse graph visits 7, then 8 |
| 8 | yes | already in Tree 3, skip |
Picture it
Animation
Shows: Kosaraju: two passes and a reversal — a rendered Manim animation.
Rendered with Manim.
Takeaway: Reversing preserves the components while destroying the order between them.
Anomaly
Predict first
A student writes this, and it looks reasonable:
A student remembers to process vertices in decreasing finish-time order, but runs the second DFS on the ORIGINAL graph instead of building the reverse graph first.
It is wrong. Say what breaks — and say it before you turn the page.
Correct: Vertex 1 can reach every other vertex forward through the original chain 1 to 2 to 3 to 4 to 5 to 6 to 7 to 8, so this single DFS call visits all eight vertices in one tree.
Build the reverse graph first, THEN run the second DFS on it, still in decreasing finish-time order.
Why: Vertex 1 can reach every other vertex forward through the original chain 1 to 2 to 3 to 4 to 5 to 6 to 7 to 8, so this single DFS call visits all eight vertices in one tree.
Trap
A student remembers to process vertices in decreasing finish-time order, but runs the second DFS on the ORIGINAL graph instead of building the reverse graph first.
\[ \text{Start DFS from vertex 1, using the original (non-reversed) edges} \]
Run DFS from vertex 1 on the original graph
Why: Vertex 1 can reach every other vertex forward through the original chain 1 to 2 to 3 to 4 to 5 to 6 to 7 to 8, so this single DFS call visits all eight vertices in one tree.
| Vertex | Reachable from 1 using the ORIGINAL edges? |
|---|---|
| 2 | yes |
| 3 | yes |
| 4 | yes |
| 5 | yes |
| 6 | yes |
| 7 | yes |
| 8 | yes |
Report one giant strongly connected component of all eight vertices
Why: This is wrong: vertex 8, for instance, cannot reach back to vertex 1 at all, so they are not mutually reachable and should never be grouped together.
Build the reverse graph first, THEN run the second DFS on it, still in decreasing finish-time order.
\[ \text{Start DFS from vertex 1, using the REVERSED edges} \]
DFS from 1 on the reverse graph reaches only 3 and 2
Why: In the reverse graph, the edges leaving the {1,2,3} group toward other groups have been flipped to point inward instead, so this DFS call cannot escape the group — it correctly stops at exactly {1, 2, 3}.
Invariant
Step through it
Step through Trap: forgetting the reverse-graph pass one row at a time. One of these columns never changes — find it, and say why it cannot.
Concept
supernode — A single point that stands in for an entire strongly connected component, once every vertex in that component has been contracted (merged) into it.
Every edge that used to run between two different components now becomes an edge between their two supernodes. Edges that stayed inside a single component simply disappear, since that component is now just one point.
Concept
Do that contraction for every strongly connected component in a graph, all at once, and the result is called the condensation of the graph.
\[ \text{Condensation: one supernode per SCC, plus every edge that ran between two different SCCs} \]
Intuition
Zoom out on the eight-vertex graph until each triangle and pair blurs into a single dot. What is left is three dots in a row, connected in the same order the clumps used to feed into each other.
All the tangled back-and-forth arrows that made each clump strongly connected are now hidden inside a single dot — only the connections between different clumps survive to the outside.
Picture it
Figure (svg): Three boxes in a row labeled with vertex sets 1,2,3 then 4,5,6 then 7,8, with an arrow from the first box to the second and another from the second box to the third.
Discussion prompt
Read the picture before the words. What is this showing, and what is the one thing it is built to make obvious? Commit to an answer, then read on.
Hint: Name the parts, then say what changes between them — and if nothing changes, say what is being held still.
Answer:
Using the three SCCs found earlier: {1,2,3}, {4,5,6}, {7,8}.
Worked example
Using the three SCCs found earlier: {1,2,3}, {4,5,6}, {7,8}.
\[ \text{Supernodes: } S_1=\{1,2,3\},\ S_2=\{4,5,6\},\ S_3=\{7,8\} \]
Keep only edges that cross between different supernodes
Why: The edge from 3 to 4 crosses from S1 into S2, and the edge from 6 to 7 crosses from S2 into S3. Every other original edge (1-2, 2-3, 3-1, 4-5, 5-6, 6-4, 7-8, 8-7) stays entirely inside one supernode and disappears.
Figure (svg): Three boxes in a row labeled with vertex sets 1,2,3 then 4,5,6 then 7,8, with an arrow from the first box to the second and another from the second box to the third.
Verify no back edge exists among the supernodes
Why: Checking every pair: S1 to S2 exists, S2 to S3 exists, but there is no edge S2 to S1, no S3 to S2, and no direct edge at all between S1 and S3 in either direction. Nothing points backward, so the condensation is a simple forward chain.
| Supernode pair | Edge exists? | Direction |
|---|---|---|
| S1 and S2 | yes | S1 to S2 only |
| S2 and S3 | yes | S2 to S3 only |
| S1 and S3 | no direct edge | (reachable only by passing through S2) |
Comparison
Comparison matrix
From Build the condensation of the eight-vertex graph: refill the Direction column from what you know. The rest of the table is as it appeared.
| Supernode pair | Edge exists? | Direction |
|---|---|---|
| S1 and S2 | yes | S1 to S2 only |
| S2 and S3 | yes | S2 to S3 only |
| S1 and S3 | no direct edge | (reachable only by passing through S2) |
Intuition
What move should we make next?
Contract every strongly connected component to a single vertex.
\[ \text{claim: the resulting graph is acyclic} \]
Same claim shape as the first proof today, and the same move. Name it — and say what you get to conclude if a cycle among components did exist.
_Look at your toolkit. Say a move number out loud before this slide advances._ A wrong guess is useful. A silent guess is not.
Concept
Suppose the condensation had a cycle among its supernodes — say an edge from one supernode to a second, and also an edge from that second supernode back to the first.
\[ S_1 \to S_2 \ \text{and}\ S_2 \to S_1 \implies \text{every vertex in } S_1 \text{ reaches every vertex in } S_2 \text{, and back} \]
But that would make every vertex across both supernodes mutually reachable, meaning they were never two separate maximal components to begin with — they should have been one bigger SCC. Since the SCCs used to build it are already maximal by definition, the condensation can never contain a cycle.
Explain it
Discussion prompt
Explain Why the condensation is always a DAG to a student a year behind you. No notation, no jargon they have not met — and it still has to be true.
Hint: If your explanation needs a symbol they have never seen, you are describing the notation rather than the idea.
Answer:
Suppose the condensation had a cycle among its supernodes — say an edge from one supernode to a second, and also an edge from that second supernode back to the first.
Picture it
Animation
Shows: Contract each component and a DAG appears — a rendered Manim animation.
Rendered with Manim.
Takeaway: Which means you can topologically sort the components even when the graph has cycles.
Estimation
Predict first
The condensation just built is itself a directed graph with three vertices, S1, S2, S3, and two edges.
Commit before you compute: what does Topologically sort the condensation itself come out to? A rough magnitude and the right form is enough — the point is to have something concrete to be wrong about.
Correct: Verify the resulting order against the condensation's edges
Why: A prediction you can defend turns the computation into a check rather than a leap of faith — and an answer that contradicts it is caught on the spot. Positions S1=1, S2=2, S3=3. Edge S1 to S2: 1 before 2, valid.
Worked example
The condensation just built is itself a directed graph with three vertices, S1, S2, S3, and two edges.
\[ V=\{S_1,S_2,S_3\},\ E=\{(S_1,S_2),(S_2,S_3)\} \]
Apply the same rule used all lesson: source before target for every edge
Why: S1 to S2 requires S1 before S2, and S2 to S3 requires S2 before S3 — chaining those two requirements together fixes the entire order.
\[ \text{Order: } S_1,\ S_2,\ S_3 \]
Verify the resulting order against the condensation's edges
Why: Positions S1=1, S2=2, S3=3. Edge S1 to S2: 1 before 2, valid. Edge S2 to S3: 2 before 3, valid. Because the condensation is guaranteed to be a DAG, it is also guaranteed to have a topological order — and here it is.
Picture it
Animation
Shows: Each line of the worked example "Topologically sort the condensation itself", appearing one at a time.
The same working the example does, in the order a tutor would write it.
Takeaway: Positions S1=1, S2=2, S3=3. Edge S1 to S2: 1 before 2, valid. Edge S2 to S3: 2 before 3, valid. Because the condensation is guaranteed to be a DAG, it is also guaranteed to have a topological order — and here it is.
Section
Section 5
Pattern
1. Check for a cycle before trusting any order
Why: With DFS finish times, look for a back edge to an ancestor still on the call stack. With Kahn's algorithm, if fewer vertices get removed than the graph actually has, the leftover vertices form a cycle.
2. To produce ONE valid order, use either the DFS finish-time method or Kahn's algorithm
Why: Sort by decreasing finish time, or repeatedly remove a vertex with in-degree zero — both run in time proportional to the size of the graph, and both are equally correct even when they disagree with each other.
\[ \text{Both run in } \Theta(|V|+|E|) \]
3. To find every strongly connected component, run Kosaraju's algorithm
Why: DFS the graph once for a finish order, reverse every edge, then DFS the reverse graph starting from vertices in decreasing finish-time order — each resulting tree is exactly one SCC.
4. Contract each SCC to a supernode and you get the condensation, which is always a DAG
Why: Since SCCs are maximal by construction, a cycle among supernodes would mean two of them should have been merged — so it never happens, and the condensation always has its own topological order.
Notation
Annotate
From The full toolkit — read this one piece at a time. What is each part doing?
On: \( \text{Both run in } \Theta(|V|+|E|) \)
Intuition
What move should we make next?
Today you proved a cyclic graph has no topological order and the condensation has no cycle.
Both were the same two moves in the same order.
Name the shared shape, and say what the extremal choice was in each. If the second one felt like a new proof, that is worth noticing.
_Look at your toolkit. Say a move number out loud before this slide advances._ A wrong guess is useful. A silent guess is not.
Analogy
Discussion prompt
Explain Decision point: two proofs, one shape by analogy to something with no CS3000 Algorithms in it at all — a queue, a recipe, a map, a bank balance, whatever fits. Then say where your analogy breaks.
Hint: An analogy that never breaks is not an analogy, it is the same idea wearing a hat. Find the seam — that is the part that is actually new.
Answer:
Today you proved a cyclic graph has no topological order and the condensation has no cycle.
Elimination
Eliminate the wrong options
Does this graph have a topological order?
3 of these 4 are wrong. Strike them one at a time, and say what rules each one out before you strike the next. The survivor is the answer.
Survives elimination: A
Why: The edges P to Q, Q to R, and R to P form a cycle among all three vertices. A topological order exists only for acyclic graphs, and no arrangement of P, Q, R in a line can avoid putting at least one edge backward, so none exists here.
Check
Consider a directed graph with three vertices, P, Q, R, and edges P to Q, Q to R, and R to P.
Check your understanding
Does this graph have a topological order?
Answer: A
Why: The edges P to Q, Q to R, and R to P form a cycle among all three vertices. A topological order exists only for acyclic graphs, and no arrangement of P, Q, R in a line can avoid putting at least one edge backward, so none exists here.
Prediction
Predict first
Using the DFS finish-time method, what is the correct topological order?
Answer it in your own words, now, with nothing to choose from. The options are on the next slide — and picking the right one off a list is an easier skill than producing it.
Correct: M, O, P, N
Why: The method sorts vertices by decreasing finish time. Ranking 8, 7, 6, 5 from largest to smallest gives M, O, P, N, which is the valid topological order produced from these finish times.
Check
A DFS on a graph with vertices M, N, O, P produces these finish times: finish(M) = 8, finish(N) = 5, finish(O) = 7, finish(P) = 6.
Check your understanding
Using the DFS finish-time method, what is the correct topological order?
Answer: A
Why: The method sorts vertices by decreasing finish time. Ranking 8, 7, 6, 5 from largest to smallest gives M, O, P, N, which is the valid topological order produced from these finish times.
Check
Partway through Kahn's algorithm on a graph with vertices W, X, Y, Z, the current in-degrees are: W = 0, X = 0, Y = 1, Z = 2.
Check your understanding
Which vertex or vertices can legally be removed next?
Answer: A
Why: Kahn's algorithm removes any vertex whose in-degree is currently zero. Both W and X qualify right now; a vertex does not need to have the single lowest in-degree in the whole graph, it only needs to reach exactly zero.
Check
A graph has vertices K, L, M, N with edges K to L, L to M, M to K, and M to N — with no edge going back from N to anything.
Check your understanding
What are the strongly connected components of this graph?
Answer: A
Why: K, L, and M form a cycle (K to L to M to K), so each one can reach the other two and back — they are mutually reachable and form one SCC. N receives an edge from M but has no path back to K, L, or M, so N stands alone as its own singleton component.
Commit first
Predict first
What is the most likely result of skipping the reversal?
Commit to an answer, then rate it — certain, fairly sure, or guessing — and write the rating down before you turn the page.
Correct: The pass can merge multiple distinct strongly connected components into one incorrect, oversized tree.
Why: Without reversing, the second pass follows the very same forward edges as pass one, so starting from the highest-finish-time vertex can reach every vertex the first pass could reach, collapsing components that are not actually mutually reachable into one wrong, oversized tree.
The rating matters as much as the answer: confident-and-wrong is the combination that survives revision, because nothing about it feels like it needs revisiting.
Check
A student runs Kosaraju's second DFS pass in decreasing finish-time order from pass one, but forgets to reverse the edges first, using the original graph instead.
Check your understanding
What is the most likely result of skipping the reversal?
Answer: A
Why: Without reversing, the second pass follows the very same forward edges as pass one, so starting from the highest-finish-time vertex can reach every vertex the first pass could reach, collapsing components that are not actually mutually reachable into one wrong, oversized tree.
Check
Suppose a graph's condensation somehow contained a cycle: an edge from SCC1 to SCC2, and also an edge from SCC2 back to SCC1.
Check your understanding
What would that imply about SCC1 and SCC2 in the original graph?
Answer: A
Why: An edge from SCC1 to SCC2 means some vertex in SCC1 reaches some vertex in SCC2, and since every vertex inside an SCC already reaches every other vertex in that same SCC, an edge back from SCC2 to SCC1 would make every vertex in each component reach every vertex in the other — so they were never two separate maximal components.
Prediction
Predict first
How many different valid topological orders does this graph have?
Answer it in your own words, now, with nothing to choose from. The options are on the next slide — and picking the right one off a list is an easier skill than producing it.
Correct: 3 — W can slide into any of the three positions, as long as U still comes before V.
Why: The only requirement is that U comes before V. W has no edges at all, so it can go before both, between them, or after both, giving exactly 3 valid orders: W, U, V and U, W, V and U, V, W.
Check
A DAG has vertices U, V, W with exactly one edge: U to V. Vertex W has no edges at all.
Check your understanding
How many different valid topological orders does this graph have?
Answer: A
Why: The only requirement is that U comes before V. W has no edges at all, so it can go before both, between them, or after both, giving exactly 3 valid orders: W, U, V and U, W, V and U, V, W.
Elimination
Eliminate the wrong options
Kosaraju's pass two should start its DFS from vertex 5. On which graph, and why vertex 5?
3 of these 4 are wrong. Strike them one at a time, and say what rules each one out before you strike the next. The survivor is the answer.
Survives elimination: A
Why: Kosaraju's second pass must run on the reverse graph, with every edge flipped, and it processes vertices in decreasing finish-time order from pass one — so it starts at vertex 5, the vertex with the highest finish time, exactly as given.
Check
After DFS pass one on a graph, the finish-time order from highest to lowest is: vertex 5, vertex 2, vertex 4, vertex 1, vertex 3.
Check your understanding
Kosaraju's pass two should start its DFS from vertex 5. On which graph, and why vertex 5?
Answer: A
Why: Kosaraju's second pass must run on the reverse graph, with every edge flipped, and it processes vertices in decreasing finish-time order from pass one — so it starts at vertex 5, the vertex with the highest finish time, exactly as given.
Concept
Moves added today: none.
That is a result, not a gap. Everything in this lesson was proved with moves you already owned.
Moves you reused today:
Both big proofs today were contradiction plus an extremal choice. The first vertex finished, the earliest vertex in the order — you are picking the extreme offender, exactly as in the root-2 proof.
Full toolkit so far: #1 through #14.
Next session opens with you naming every one of these from memory, before any new material.
Counterexample
Discussion prompt
Next session opens with you naming every one of these from memory, before any new material.
That is stated as though it always holds. Do one of two things: produce a case where it fails, or say precisely what rules such a case out. "It just does" is not on the menu.
Hint: Hunt at the extremes first — zero, one, negative, empty, equal. If every extreme survives, the reason they survive is the proof.
Connect it up
Draw it
One page, no notation unless you need it: draw how these connect — Directed Graphs & Topological Order · Ordering by DFS Finish Time · Kahn's Algorithm · Strongly Connected Components · Putting It Together. Put an arrow wherever one of them is what makes another possible, and label the arrow with why.
Recap
A topological order lines up a graph's vertices so every edge points forward — and one exists only when the graph has no cycle.
| Technique | Core move | Running time |
|---|---|---|
| DFS finish-time order | Sort vertices by decreasing finish time | V + E |
| Kahn's algorithm | Repeatedly remove an in-degree-zero vertex | V + E |
| Kosaraju's SCCs | DFS, reverse the graph, DFS again | V + E |
| Condensation | Contract each SCC to one point | always a DAG |
Want this taught 1-on-1? Alexander tutors CS3000 Algorithms — $55/session, free consultation.