Home / COMP2870 / Graph algorithms

Graph Algorithms

COMP2870 · weeks 1–3

Follows the 2026/27 lecture notes by K. Vušković. The animations use the same examples.

How to use this page

This page is for priming. The goal is to learn the shape of each topic before the lecture: the problem, the key idea, what the algorithm looks like while it runs, and the questions the proof has to answer. You don't need to master anything here. When the lecture fills in the details, you'll already have somewhere to put them.

  1. Read the map first (2 min). There are six problems, three design techniques, and one proof pattern that keeps coming back.
  2. Work up through the levels. Each algorithm has three: Simple (just the mechanism), Notes example (the one from the lecture), and Harder (a bigger graph to test yourself).
  3. For each animation, guess before you click. Before pressing next, say which vertex or edge you expect to be picked. A wrong guess you then correct sticks far better than passively watching the answer.
  4. Keep the "carry into the lecture" questions in mind. They are what the proofs in the notes are really answering.
  5. Do the self-test the next day. Retrieval practice after a gap is what moves this into long-term memory.
  6. If a symbol or a proof step feels shaky (∀, ⇒, set-builder, induction, big-O), use the Maths refresher tab.

0. Lecture 1: what was said

Summary of lecture 1 (28 Sep).

The module and how it runs

What was saidWhat it means for you
She teaches the first 3 weeks: graph algorithms. It builds on logic and methods of proof, and on last year's graph theory, which she taught.Revise proof by induction and contradiction. Every correctness proof here uses one of them. See the Maths refresher → proof methods.
6 algorithms: MST (Prim, Kruskal); shortest paths from one source (Dijkstra) and between all pairs (Floyd–Warshall); max flow (Ford–Fulkerson, "more difficult, none of you have seen it"); and matching.Those are the first five rows of the map. For all pairs you could run Dijkstra n times, but the point is a specialised, faster method.
The focus is proofs of correctness, not just how the algorithms work. These are provable algorithms: for a given input the output is proven exactly right, unlike machine learning.Knowing how to run Prim won't be enough. You have to be able to prove it's correct.
Why study algorithms from the 1950s? They solve fundamental problems that turn up everywhere, they're efficient (roughly between O(n²) and O(n³)), and understanding the proofs builds critical thinking. It also lets you adapt an algorithm when your graph has special properties.When studying a proof, ask which property of the input each step uses. That is the skill you need to adapt an algorithm.
The proofs are "a couple of categories harder" than before. "We'll go slowly."Expect to reread each proof several times. That's normal.
Notes: 25–27 examinable pages, "very dense": definitions, theorems, proofs. The Minerva version has extra material. Printed copies are available at the maths lunch hour (sign in).The extra material is §5.2 (optional).

How you're expected to learn

What was saidWhat it means for you
Paper and pencil (or an iPad), not laptops. She draws "how my brain works" while going through a proof.Copy the drawings, not just the words. The pictures are the strategy of the proof.
Exams and coursework expect proofs in exactly the style of the notes: "every word in the right place, every sentence justified".Practise writing proofs in the notes' own phrasing (see part G of the worksheet).
After each lecture: read the notes up to where the lecture stopped, and make your own handwritten, visual notes (colours, pictures). Then do the activity sheets and bring questions to tutorials.This primer is for before the lecture. Your handwritten notes are for after it. Don't skip them.
The lectures are interactive: answer her questions by raising your hand or calling out. No chatting: one warning, then you're asked to leave.
Assessment: a test in January plus the final exam. Portfolios: at least 6 of 9 (possibly 7) must be submitted by their own deadlines, or you fail. The point is to submit early, get feedback, and improve. Last year's exam results were bad.Put every portfolio deadline in your calendar now. Read the module handbook on Minerva (from Sam Wilson) when it appears, especially the advice section.

The terminology she reviewed, and the points she stressed

It all maps onto section 2, and you can practise it in the notation worksheet. The points below are the ones she made a point of, so they're likely to matter in proofs and exams.

  1. "Graph" means simple graph. E is a set of 2-element subsets of V. Why: for these problems, parallel edges or loops add nothing. For a shortest path you'd always use the cheaper of two parallel edges, so you can delete the other. A multigraph allows loops and multiple edges. A digraph's edges are ordered pairs.
  2. Abuse of notation is allowed only once it's been established. Writing uv for {u,v} and G − v for G − {v} is fine because the notes set it up. In your own work you can't invent notation unless you define it first. Otherwise, stick to the conventions of the notes.
  3. uv means different things in different contexts. In a graph uv = vu. In a digraph, uv is the arc from u to v, and vu is a different arc.
  4. In a simple graph a walk can be written as just its vertices, since there's exactly one edge between adjacent vertices. So v₁, v₂, v₁ is a walk: each consecutive pair is adjacent, and that's the only condition.
  5. Why is a cycle a "closed trail with distinct vertices except start = end", and not a "closed path"? Because a path can't repeat any vertex, including its first one at the end. So a "closed path" can't exist. The wording is chosen carefully.
  6. A drawing of one example is not a proof. To prove "for every graph…", you can't check one particular graph. Her abstract drawings (a wiggly line for "some trail") stand for all possible cases. A picture of a specific graph is only an example.
  7. Connected is a ∀∃ statement: for every pair of vertices there exists a path. There may be many paths; you only need one.
  8. Component = inclusion-wise maximal connected induced subgraph. Her example: a connected piece that is missing an edge between two of its vertices isn't maximal, because you can add the edge. After adding it, nothing more can be added, so it's a component.
  9. Leaf lemma, quoted carefully: every tree with at least 2 vertices has at least 2 leaves. A single vertex is a tree with no leaves. The lemma is the standard tool for induction on the number of vertices.
  10. Forest: every connected component is a tree (equivalently, it has no cycle).
  11. "Weighted graph" means edge-weighted throughout this part of the module. Vertex weights exist in other settings but aren't used here.

Turning the "contract" into a checklist. For each of the six algorithms, make sure you can:

  1. State the problem precisely: input, output, and any restrictions (e.g. w ≥ 0, connected, no negative closed walks).
  2. Write the pseudocode with the notes' line numbers. The proofs refer to lines ("by line 5…").
  3. Trace it on a small graph and produce the iteration table the notes use.
  4. Give the proof skeleton: what is being inducted on, what the invariant or claim is, and where the key inequality comes from.
  5. State the running time and which data structure gives it.

The animations below cover points 1–3. Points 4–5 are summarised under each one.

Second half (after the break)

What was coveredWhere it is here
Lemma 2.2, proved interactively on the board: classify the statement first, the direct method for both directions, and a contradiction inside (⇐).Section 2½: the proof line by line, animations, and the mistakes she flagged
Her advice on proofs: "Your job for now is to understand these proofs, very deeply. Don't worry about how do I come up with a proof idea like this? That's not your worry at the moment. The next step is writing proofs, but one thing at a time."Study each proof until you can explain every line. The "why this line" tables are built for this.
Application: make several pins on a circuit electrically equivalent using the least wire. Model it as a complete graph with distances as weights. You want a path between every pair of pins with minimum total wire, which is a minimum weight spanning tree.Section 3
Formal definitions: weight function w : E → ℕ; the weight of a spanning tree, w(T) = Σe∈E(T) w(e); T has minimum weight if w(T) ≤ w(T′) for every spanning tree T′; and the MST problem.Section 3, definitions box
A reminder of the tree facts from Theorem 2.3: n − 1 edges, exactly one path between any pair of vertices.Vocabulary → Theorem 2.3
Optimisation problems and greedy algorithms: "do whatever looks best at the moment, keep going, and hope it ends up globally optimal." It doesn't always work, but it does for MST. Why it works (matroid theory) is beyond this course, but there's optional reading in the notes.The map (three techniques) and section 3
Prim's algorithm, informally: grow a tree from one vertex u. Label each vertex L(v) = w(uv), or ∞ if there's no edge. Repeatedly add the outside vertex with the smallest label, then update the labels of vertices adjacent to the one just added. Stop when every vertex is in.The Prim animation shows exactly this
Where the lecture stopped: Prim's algorithm was described (pseudocode lines 1–8 in §2.2), but not yet proved.
Her instruction: read the notes up to where the lecture stopped, i.e. §1 to the Prim algorithm in §2.2 (pages 1–5). Make your own handwritten, visual notes of the definitions and the Lemma 2.2 proof. Then do the activity sheet.
Next lecture, probably: the worked Prim example (Figure 1), Theorem 2.4 (Prim is correct), which is induction on |VT| with an exchange argument, then Prim's running time and Kruskal. Before then, step through the Prim animation and read "Why it's correct" under it.

1. The map

ProblemInputAlgorithmTechniqueTime
Minimum weight spanning treeconnected graph, w: E→ℕPrim, KruskalgreedyO(m + n log n), O(m log n)
Single-source shortest pathsdigraph, w: E→ℕ (≥ 0)DijkstragreedyO(m + n log n)
All-pairs shortest pathsdigraph, w: E→ℤ, no negative closed walkFloyd–Warshalldynamic programmingO(n³)
Maximum flownetwork, c: E→ℕ, source s, sink tFord–Fulkersoniterative improvementO(nmU)
Max matching, bipartitebipartite graphreduce to max flowreductionO(nm)
Max matching, general optionalany graphEdmonds' blossomaugmenting pathsO(n⁴)

Throughout, n = |V| (vertices) and m = |E| (edges).

Three design techniques

Greedy: make the choice that looks best right now and never undo it. This usually doesn't give an optimal answer. For MST and for Dijkstra it provably does, and the proof is the interesting part.
Dynamic programming: solve smaller subproblems, store the answers, and combine them. This works when every part of an optimal solution is itself optimal for its own subproblem.
Iterative improvement: start with any valid solution and keep improving it (augmenting) until you can't. Then produce a certificate that proves nothing better exists.

The proof pattern you'll see everywhere: induction on the size of the partial solution plus an exchange argument. The claim is "my partial answer is contained in some optimal answer". If an optimal answer disagrees with you, swap one of its edges for yours and show the result is no worse.

2. Vocabulary you're expected to be fluent in

Each term has three lines: formal (as in the notes), ELI5 (the plain idea), and analogy. One picture runs through all the analogies: a graph is a map of towns (vertices) joined by roads (edges).

Basics

graph G = (V, E)
formal V is a finite set of vertices. E is a set of 2-element subsets {u,v} of V, written uv.
ELI5 Some dots, and some lines that each join two dots. There's at most one line between any two dots, and no line from a dot back to itself.
analogy Towns, and the direct roads between them.
adjacent / neighbours, N(v); incident; endvertices
formal u,v are adjacent if uv ∈ E. N(v) = {u : uv ∈ E}. u is incident with e if u ∈ e.
ELI5 Two dots are neighbours if a line joins them. A line "touches" (is incident with) the two dots at its ends.
analogy N(v) is the list of towns you can reach from v in one drive. A road is incident with the two towns it connects.
walk → trail → path; closed walk; cycle
formal Walk: v₀,e₁,v₁,…,ek,vk, with each edge joining the vertices either side of it. Trail: no repeated edge. Path: no repeated vertex. Closed: v₀ = vk. Cycle: a closed trail whose only repeat is the start/end.
ELI5 A walk is any route. A trail never uses the same line twice. A path never visits the same dot twice. A cycle is a loop back home with no other repeats.
analogy Walk: a wandering drive, going wherever you like, any number of times. Trail: a snowplough that never clears the same road twice. Path: a tourist who refuses to see the same town twice. Cycle: a bus route that starts and ends at the depot and visits each stop once.
note Every path is a trail, and every trail is a walk. The reverse is not true.

Subgraphs (being explained right now)

Same base graph G each time. Bold = kept, faint dashed = thrown away.

subgraph H ⊆ G (and supergraph)
formal V(H) ⊆ V(G) and E(H) ⊆ E(G), and H must itself be a graph. G is then a supergraph of H.
ELI5 Keep some dots and some lines, rubbing out the rest. One rule: you can't keep a line if you've rubbed out a dot at either end.
analogy A delivery driver's personal map, showing only the towns and roads they use. It can leave out roads even between towns that are on it. The full national map is the supergraph.
spanning subgraph
formal H ⊆ G and V(H) = V(G).
ELI5 Keep every dot. You may throw away lines.
analogy A snowstorm: some roads close, but every town is still on the map (possibly cut off).
why you care A spanning tree is a spanning subgraph that is a tree. It is the whole point of §2.
proper subgraph
formal H ⊆ G and H ≠ G.
ELI5 A subgraph that is missing at least one thing, either a dot or a line.
analogy Like "proper subset" (⊂ vs ⊆): a slice of the pizza, not the whole pizza. G counts as a subgraph of itself, but not as a proper one.
induced subgraph G[U]
formal Vertex set U, and edge set {xy ∈ E(G) : x,y ∈ U}. "The subgraph of G induced by U."
ELI5 You only choose the dots. Every line between chosen dots comes along automatically; you're not allowed to drop any of them.
analogy A party: you choose the guest list (U), and every friendship between guests comes too. You can't un-friend two guests at the door. Or: zoom a map in on a region, and you see all the roads inside it.
G − S (delete vertices)
formal Remove the vertices in S and every edge touching them. G − S = G[V(G) ∖ S]. For one vertex, write G − v.
ELI5 Rub out some dots, and any line that loses an end disappears with them.
analogy Towns flooded: the town goes, and so does every road into it.
note G − S is always an induced subgraph.
G − F (delete edges)
formal V(G − F) = V(G) and E(G − F) = E(G) ∖ F. For one edge, write G − e.
ELI5 Rub out some lines only. All the dots stay.
analogy Roadworks: some roads closed, no towns lost.
note G − F is always a spanning subgraph. G − e is how the notes define a cut-edge.

The confusion to avoid: spanning vs induced

Spanning: the vertices are fixed (all of them) and you choose the edges.
Induced: you choose the vertices, and the edges are then fixed (all the ones between them).
They are "opposite" freedoms. The only subgraph that is both spanning and induced is G itself.

Quick check (answer in your head, then click) (1) Is G a subgraph of itself? Yes. A spanning subgraph? Yes. Induced? Yes, G = G[V]. Proper? No.
(2) Is G − e spanning? Yes. Induced? No, because e's two ends are still there but e is gone.
(3) Is G − v induced? Yes, it equals G[V ∖ {v}]. Spanning? No, v is missing.
(4) Given U, how many induced subgraphs have vertex set U? Exactly one. How many subgraphs (in general)? As many as there are choices of which edges between them to keep.

Connectivity and trees

connected she said: "this needs to be ingrained in your brain"
formal G is connected if for every pair of vertices u, v ∈ V(G) there is a (u,v)-path in G.
symbols ∀u, v ∈ V(G)  ∃ a (u,v)-path in G.   This is "doubly quantified": first ∀, then ∃.
ELI5 Pick any two dots. Can you always trace from one to the other along the lines? If yes for every choice, the graph is connected. It's all in one piece.
analogy A road network where you can drive from any town to any other town, maybe through other towns and not necessarily directly.

Reading the definition carefully

  • "a path", not "an edge": u and v don't need to be adjacent. The path may pass through other vertices. (If every pair is adjacent, the graph is complete, which is much stronger.)
  • "there is a path" means at least one. Different pairs may use different paths, and a pair may have many paths. You only need one each.
  • The ∀ ranges over every pair. Checking a few pairs proves nothing. Checking one bad pair disproves it.
  • Tiny cases: a graph with one vertex is connected, since the only "pair" u = v is joined by the length-0 path u.

How to use it in a proof

  • To prove G is connected: "Let u, v ∈ V(G). [Build or find a (u,v)-path.] Hence G is connected." (This is the (⇒) step of Lemma 2.2.)
  • To prove G is NOT connected: exhibit one pair u, v with no (u,v)-path. The negation is ∃u,v ∀paths: not a (u,v)-path.
  • To use "G is connected" as a given: "Since G is connected, there is a (u,v)-path P in G." You get a path for whichever u, v you choose.

Equivalent views (all the same property):

  • G has exactly one connected component.
  • No gap: for every split of V into two non-empty parts S and V ∖ S, some edge crosses from S to V ∖ S. (If none did, no path could get from S to V ∖ S.) The Kruskal proof uses exactly this: "since G is connected, there is an edge with one end in V(T′) and one end outside".
  • G has a spanning tree (Lemma 2.2).
disconnected
formal Not connected: ∃u, v ∈ V(G) with no (u,v)-path.
ELI5 At least two pieces. Some pair of dots can't reach each other.
analogy An island with no bridge or ferry.
connected component
formal An inclusion-wise maximal connected induced subgraph of G.
ELI5 One whole piece: connected, and you can't add anything to it without breaking connectivity. "Induced" means it keeps all the edges between its vertices.
analogy A country of islands with no ferries: each island (with all its roads) is a component.
lecture example A connected piece that is missing one edge between two of its vertices is not maximal, because you can add that edge. Once nothing more can be added, it's a component.
forest (acyclic), tree, leaf
formal A forest has no cycle. A tree is a connected forest. A leaf is a vertex of degree 1.
ELI5 A tree is all in one piece, with no loops. A forest is several trees side by side. A leaf is a dot with only one line.
analogy A tree is like a family tree or the folders on your computer: exactly one route between any two things. A leaf is a dead-end town with only one road in.
cut-edge (bridge)
formal In connected G, e is a cut-edge if G − e is disconnected. Lemma 2.1: e is not a cut-edge ⇔ e lies on a cycle.
ELI5 A line that you can't remove without splitting the picture in two.
analogy The only bridge to an island. Lemma 2.1 in town terms: a road can close without cutting anyone off exactly when there's a detour, and a detour plus the road makes a cycle.
Theorem 2.3 (used constantly)
formal For n-vertex G, these are equivalent: (a) connected and acyclic, (b) connected with n−1 edges, (c) acyclic with n−1 edges, (d) exactly one path between each pair of vertices.
ELI5 n−1 lines is the magic number. With fewer, you can't join n dots. With more, you're forced into a loop.
analogy Linking n towns with the fewest roads needs exactly n−1 roads. Add one more road and you've built exactly one round trip. That's the "T* + e has a unique cycle" step in every MST proof.

Weights and directions

(edge-)weighted graph
formal G together with w: E → ℕ (or ℤ).
ELI5 Every line has a number written on it.
analogy Each road's length, toll or travel time.
directed graph (digraph) D = (V, A)
formal The arcs are ordered pairs (x,y), so xy ≠ yx. Paths and cycles have to follow the directions.
ELI5 The lines are arrows, and you can only travel the way they point.
analogy One-way streets. Or following someone online: you following them doesn't mean they follow you.

2½. Lemmas 2.1 & 2.2: the first proofs

Proved on the board in lecture 1 (second half). These two lemmas are the foundation for everything in §2: every MST proof uses "an edge on a cycle can be removed safely".

Lemma 2.1. Let G be a connected graph. An edge e ∈ E(G) is not a cut-edge if and only if it belongs to a cycle.

Lemma 2.2. A graph has a spanning tree if and only if it is connected.

Step 0: classify the statement before writing anything

This is the routine she walked through before the first line of the proof. It comes from the logic part of the course (see the refresher on quantifiers and logic).

Question to askLemma 2.2What it tells you to write
1. Is there a quantifier?Yes, a hidden ∀: "for every graph G…"Start with "Let G be a graph." This picks an arbitrary element of the universe of all graphs and assumes nothing else about it.
2. Which connective?⇔ (if and only if)Two separate proofs: (⇒) and (⇐). One direction is usually easier; here it's (⇒).
3. Which method for each implication?Direct for both. A contradiction appears later, inside (⇐).Direct method: assume the hypothesis, then argue until you reach the conclusion.

In symbols: ∀G ( G has a spanning tree ⇔ G is connected ). For Lemma 2.1: ∀G connected, ∀e ∈ E(G): ( e is not a cut-edge ⇔ e lies on a cycle of G ).

Lemma 2.1, seen

edge cycle / detour edge being removed removed

Proof of Lemma 2.1 (from COMP1870; the notes quote it without proof, but you should be able to produce it)

Let G be a connected graph and let e = xy ∈ E(G).

(⇐) Suppose e lies on a cycle C of G. Then C − e is an (x,y)-path P that does not use e. Let u, v ∈ V(G). Since G is connected, there is a (u,v)-path Q in G. If e ∉ E(Q), then Q is a (u,v)-path in G − e. Otherwise, replacing e in Q by P gives a (u,v)-walk in G − e, and every (u,v)-walk contains a (u,v)-path. So G − e is connected, i.e. e is not a cut-edge.

(⇒) Suppose e is not a cut-edge, i.e. G − e is connected. Then there is an (x,y)-path P in G − e. Since xy ∉ E(G − e), P has at least 2 edges, so P together with e is a cycle of G containing e. □

Lemma 2.2: the board proof, line by line

Line of the proofWhy this line
Let G be a graph.The statement is ∀G, so take an arbitrary G.
(⇒) the easier direction
Assume G has a spanning tree T.Direct method: assume the hypothesis. Give it a name so you can refer to it.
Since T ⊆ G, every path in T is also a path in G.The definition of a subgraph: V(T) ⊆ V(G) and E(T) ⊆ E(G). Here ⊆ between graphs means "subgraph", not "subset".
Since T is spanning and connected, it follows that G is connected.Unpacking "connected" (a ∀∃ statement): take any u, v ∈ V(G). Since T is spanning, u, v ∈ V(T). Since T is connected, there is a (u,v)-path in T, and that path is in G.
(⇐) the harder direction
Assume G is connected.Direct method again.
Let T be a connected spanning subgraph of G with the fewest edges.Extremal choice. Such a T exists because G itself is a connected spanning subgraph of G, so the set of candidates is non-empty.
We now prove that T is a tree.That's all that's left. T is already spanning and connected, so it only remains to show it is acyclic. A spanning subgraph that is a tree is a spanning tree.
Suppose, for a contradiction, that T contains a cycle C.The contradiction starts here, inside the direction, not at the top of the proof. Name the cycle C.
Let e ∈ E(C).Any edge of the cycle will do.
By Lemma 2.1, e is not a cut-edge of T, so T − e is connected.Lemma 2.1 is applied to T, which is connected and has e on a cycle. This is why she left Lemma 2.1 on the board.
T − e is spanning, since no vertices were removed, and it has fewer edges than T.G − F is always spanning.
This contradicts our choice of T. Therefore T is a tree, and so it is a spanning tree of G. □The standard way to close an extremal-choice argument.

Lemma 2.2 (⇐), seen: why "fewest edges" works

current subgraph a cycle in it edge to delete deleted

Points she stressed

  • Don't open with "assume a contradiction". At the very start, the quantifier and the ⇔ decide the structure: "Let G be a graph", then two directions. A contradiction can appear later, inside one direction.
  • Name things ("call it T", "call it C") so you can refer to them. This is also how the notes read.
  • The contradiction assumption must be about T, not G. It's easy to slip and write "suppose G has a cycle", but G may well have cycles, and that contradicts nothing. It's T that can't have one.
  • Check that the extremal object exists. "Choose the one with the fewest edges" needs at least one candidate. G itself is one.
  • Every step names its reason: "by Lemma 2.1", "since T ⊆ G", "no vertices were removed".
  • "Watching me do it, it all makes sense, but until you sit down and work through this proof yourself, it's not going to sink in." So do the drill below from a blank page.
  • Right now, the goal is understanding, not invention. "Don't worry about how you'd come up with a proof idea like this. Your only worry is to understand these proofs, very deeply." Writing your own proofs comes next.

Carry into the next lecture

3. Minimum weight spanning trees

Problem. You are given a connected graph with edge weights w: E → ℕ. Find a spanning tree T whose total weight w(T) = Σ w(e) is as small as possible. Typical uses: wiring n pins with the least wire, or the cheapest road network that still links every town.

The definitions, as given in lecture (learn them word for word)

Let G = (V, E) be a graph with a weight function w : E → ℕ, i.e. for every e ∈ E there is an associated weight w(e).

For a spanning tree T of G, the weight of T is   w(T) = Σe ∈ E(T) w(e).

A spanning tree T is a minimum weight spanning tree of G if for all spanning trees T′ of G, w(T) ≤ w(T′).

Minimum Weight Spanning Tree Problem. Given a connected weighted graph G, find a spanning tree of G of minimum weight.

Reading notes:

  • "Minimum" is defined with a ∀: T is compared against every spanning tree. To prove T is an MST, you must beat or tie all of them, not just the ones you tried.
  • It's "≤", not "<", so ties are allowed and MSTs need not be unique. That's why the notes say "a minimum weight spanning tree".
  • Why does G have to be connected? By Lemma 2.2, that's exactly when a spanning tree exists. There are finitely many spanning trees, so one of them has minimum weight.
  • "Weighted" means edge-weighted throughout (the convention from lecture).

Optimisation problems and greedy algorithms (§2.1). An optimisation problem asks for the best of all feasible solutions under some cost. Here the feasible solutions are the spanning trees and the cost is w(T), to be minimised. A greedy algorithm makes the choice that is locally best at each step and never reconsiders it, hoping that this leads to a global optimum. In general it doesn't. For MST it provably does, and that proof is Theorem 2.4. (The general theory of when greedy works involves matroids and is optional reading.)

Facts to know. A graph has a spanning tree ⇔ it is connected (Lemma 2.2). A spanning tree always has n−1 edges. The MST need not be unique, but its weight is.

Prim's algorithm: grow one tree

Start from a single vertex. Repeatedly add the cheapest edge that leaves the tree, i.e. the one with exactly one endpoint inside. Each outside vertex v keeps a label L(v), the cheapest known edge joining it to the tree, so finding the minimum is fast.
1  E_T ← ∅
2  V_T ← {u}                         any start vertex
3  for v ∉ V_T:  L(v) ← w(uv)        (∞ if no edge), e_v ← uv
4  while V_T ≠ V:
5      x ← vertex outside V_T with minimum L(x);  e ← e_x
6      E_T ← E_T ∪ {e}
7      V_T ← V_T ∪ {x}
8      for v ∉ V_T:  if w(vx) < L(v):  L(v) ← w(vx), e_v ← vx

tree current best edge ev chosen now · orange numbers = labels L(v)

Why it's correct (Theorem 2.4), the shape of the proof. Induction on |VT|. The claim is "T is a subtree of some MST T*". When edge e = xy is added, either e ∈ T* (done), or T* + e contains a unique cycle C. C crosses from VT to outside once via e, so it must cross back via some other edge e′. Swap them: T** = T* + e − e′ is still a spanning tree, and w(e) ≤ w(e′) because line 5 picked the minimum. So T** is also an MST, and it contains T + e.

Cost. With an array of labels, line 5 is O(n) and runs n times, giving O(n²). With a Fibonacci heap (you'll meet it later in COMP2870) the total is O(m + n log n). For a maximum spanning tree, replace min with max.

Kruskal's algorithm: merge a forest

Sort all edges by weight. Go through them cheapest first and accept an edge unless it would create a cycle, i.e. unless both of its endpoints are already in the same component. The accepted edges form a forest that gradually merges into one tree.
1  sort edges: w(e_1) ≤ w(e_2) ≤ … ≤ w(e_m)
2  E_T ← ∅,  V_T ← V                 every vertex is its own component
3  for i = 1 … m:
       if T + e_i is acyclic:  E_T ← E_T ∪ {e_i}

colour = connected component accepted examining would make a cycle

Why it's correct (Theorem 2.5). (1) T is spanning and connected. If it weren't, some edge of G would join two components of T. That edge creates no cycle, so line 3 would have accepted it. (2) T is minimum. Take the MST T* that shares the most edges with T. Let ei be the first edge (in sorted order) that is in T but not in T*. T* + ei has a cycle containing some ej ∉ T with j ≥ i, so w(ei) ≤ w(ej). Then T* + ei − ej is an MST sharing more edges with T, which contradicts the choice of T*. This is the same exchange trick as for Prim, framed as a contradiction.

Cost. Sorting takes O(m log m) = O(m log n), since m ≤ n². The cycle test uses a union–find structure: find tells you which component a vertex is in, and union merges two components. That gives O(m log n) in total. Rule of thumb: Prim is better for dense graphs, Kruskal is better in practice for sparse ones.

Aside: a Steiner tree only has to span a chosen subset V′ ⊂ V. That small change makes the problem NP-complete, so no efficient algorithm is known.

Carry into the lecture

4. Shortest paths

Setting. A weighted directed graph (think of one-way streets). The weight of a path is the sum of its edge weights. dist(u,v) is the minimum weight of a (u,v)-path, or ∞ if no such path exists. A shortest path is one that achieves dist.

Dijkstra: single source, non-negative weights

Keep a set T of vertices whose distance is final. Each outside vertex v has a label L(v) = the length of the shortest path from s to v that uses only T-vertices before the last step. Repeatedly finalise the outside vertex with the smallest label, then relax its out-edges: L(v) ← min(L(v), L(v′) + w(v′v)).
1  for v ≠ s:  L(v) ← w(sv)          (∞ if no edge)
2  L(s) ← 0
3  T ← {s}
4  while T ≠ V:
5      v′ ← vertex ∉ T with minimum L(v′)
6      T ← T ∪ {v′}
7      for v ∉ T:  if L(v′) + w(v′v) < L(v):  L(v) ← L(v′) + w(v′v)

shortest-path tree edge giving current L(v) just finalised / relaxed · black vertex = in T (final)

Spot the similarity. This is Prim's skeleton with a different label. Prim uses L(v) = w(xv), the cost to attach one more edge. Dijkstra uses L(v) = L(v′) + w(v′v), the cost of the whole path from s.

Why it's correct (Theorem 3.1). Induction on |T| with two invariants: (a) for v ∈ T, L(v) = dist(s,v); (b) for v ∉ T, L(v) = the shortest path to v whose other vertices are all in T. The key step: suppose v′ is picked but L(v′) is not the true distance. Then a genuinely shorter path leaves T at some earlier vertex v″, with L(v″) ≤ (part of that path) < L(v′). But line 5 picked v′ as the minimum, a contradiction. The step "a prefix of a path is no longer than the path" needs w ≥ 0.

Cost. O(m + n log n) with a Fibonacci heap, the same analysis as for Prim.

Why negative weights break Dijkstra

Floyd–Warshall: all pairs, negative edges allowed

Running Dijkstra from every vertex works when all weights are positive. Floyd–Warshall handles integer weights of either sign, as long as there is no closed walk of negative weight. Otherwise "shortest" is meaningless, because you could go round the negative loop forever.

Dynamic programming. Number the vertices 1…n. Let dk(u,v) be the shortest u→v distance when the only intermediate vertices allowed are 1,…,k. When vertex k is added, the best path either avoids k or goes through k once:

dk(u,v) = min{ dk−1(u,v), dk−1(u,k) + dk−1(k,v) }

with d0(u,u) = 0, d0(u,v) = w(uv) if the edge exists, and ∞ otherwise. The answer is dn.
1–6  d_0 ← adjacency weights (0 on diagonal, ∞ for non-edges)
7    for k ← 1 to n:                  k MUST be the outer loop
8      for u ∈ V:
9        for v ∈ V:
10         d_k(u,v) ← min{ d_{k−1}(u,v), d_{k−1}(u,k) + d_{k−1}(k,v) }

shaded = row k and column k, the only entries each update reads · orange = entry improved in this round

Why it's correct (Theorem 3.2). Induction on k. The claim is dk(u,v) = the distance from u to v in G[{u,v,1,…,k}]. The proof has two inequalities. (≤) Joining a shortest u→k path and a shortest k→v path gives a walk. Split off any closed part, which has weight ≥ 0 because there are no negative closed walks, and you're left with a path that is no longer. (≥) A shortest path either avoids k or splits at k into two shorter subproblems.

Cost. Three nested loops, so O(n³).

Carry into the lecture

5. Maximum flow

Setting. A network is a digraph with capacities c: E → ℕ, a source s and a sink t. A flow f: E → ℕ is feasible if it satisfies two constraints:

The value of the flow is val(f) = f⁻(t) − f⁺(t), the net flow into t. The goal is a feasible flow of maximum value.

f-augmenting path
An s→t path that ignores edge directions. Forward edges must have spare capacity (f < c). Backward edges must carry some flow (f > 0). Pushing flow "backwards" means cancelling flow that was sent earlier, i.e. rerouting it.
leeway ε
The minimum over the path of (c − f) on forward edges and f on backward edges. Adding ε forward and subtracting ε backward gives a feasible flow with value val(f) + ε (Lemma 4.1).
source/sink cut [S,T]
A partition of V with s ∈ S and t ∈ T. Its capacity cap(S,T) is the sum of c over edges from S to T only.
Weak duality (Cor. 4.3)
val(f) ≤ cap(S,T) for every feasible flow and every cut, because all flow has to cross the cut. So if you ever find a flow and a cut with equal values, both are optimal.

Ford–Fulkerson (labelling algorithm)

Search from s for vertices reachable along edges with positive leeway. R is the set of vertices Reached so far, and S ⊆ R is the set already Searched from. If t gets reached ("breakthrough"), augment along the path and repeat. If the search runs out (R = S), then [S, V∖S] is a cut whose capacity equals val(f). By weak duality the flow is maximum.
R ← {s}, S ← ∅
repeat:  pick v ∈ R∖S
   for each edge vw leaving v:   if f(vw) < c(vw)  → add w to R   (forward)
   for each edge uv entering v:  if f(uv) > 0      → add u to R   (backward)
   add v to S
   if t ∈ R:  trace back → augmenting path
   if R = S:  return cut [S, V∖S]

labels f/c empty full forward on path backward on path · black = searched (S), orange ring = reached (R∖S)

Max-Flow Min-Cut Theorem (4.4). In every network, the maximum flow value equals the minimum cut capacity. Proof idea: each augmentation raises val by at least 1 and the capacities are integers, so the algorithm stops. When it stops, every S→T edge is full and every T→S edge is empty, so val(f) = cap(S,T).

Cost. Each labelling pass is O(m) (a DFS or BFS), and there are at most val(f*) ≤ nU augmentations, where U = max capacity. That gives O(nmU). This is exponential in the input length, because U is written in binary. Capacity scaling improves it to O(nm log U).

Carry into the lecture

6. Maximum matchings in bipartite graphs

A matching M ⊆ E is a set of edges no two of which share a vertex. A vertex is M-saturated if some edge of M touches it. M is perfect if every vertex is saturated, and maximum if no matching has more edges. A graph is bipartite (V₁, V₂) if every edge goes between V₁ and V₂. Example: people and jobs, where each person does at most one job and each job needs one person.

Reduction to maximum flow

Build a network G′ from G: (1) direct every edge V₁ → V₂; (2) add a source s with an edge s → each vertex of V₁; (3) add a sink t with an edge from each vertex of V₂ → t; (4) give every edge capacity 1. Then run Ford–Fulkerson from the zero flow. The flow stays integral (0 or 1 on each edge), and M = {middle edges with flow 1} is a maximum matching.

forward on augmenting path backward = "un-match" flow 1 / matched

Why it's correct (Theorem 5.1). Each u ∈ V₁ has only one incoming edge (su, capacity 1). By conservation, at most one of its outgoing edges can carry flow, and symmetrically for V₂ with t. So flow-1 edges form a matching. In the other direction, any matching M′ gives a feasible flow of value |M′|. So a bigger matching would give a bigger flow, which contradicts maximality.

Notice. The last augmenting path in level 2, s→2→a←1→b←3→c→t, alternates between unmatched and matched edges. That is exactly an M-augmenting path in G, and it is the bridge to the next section.

Cost. O(nm). Faster methods exist: Hopcroft–Karp runs in O(√n·m).

Carry into the lecture

7. Beyond bipartite: Berge & Edmonds optional in the notes (§5.2)

An M-alternating path uses edges that alternate between not-in-M and in-M. It is M-augmenting if both of its ends are unsaturated. Flipping it (matched ↔ unmatched) grows |M| by 1.

Berge's Theorem (1957). M is maximum ⇔ there is no M-augmenting path.
So every matching algorithm has the same outline: find an augmenting path, flip it, and repeat (at most n/2 times).

In bipartite graphs, searching for alternating paths is easy. In general graphs, odd cycles cause trouble: a vertex can be reached along a path of either parity. Edmonds' fix (1965) is to spot the odd cycle (a blossom), contract it to a single super-vertex, keep searching, and expand it again at the end.

This is Figure 15/16 from the notes. Edmonds' original algorithm runs in O(n⁴). The fastest known, Micali–Vazirani, runs in O(√n·m).

8. Self-test (do this tomorrow, not today)

1. State Theorem 2.3 from memory. Which part tells you that adding an edge to a tree makes exactly one cycle?(a) connected + acyclic ⇔ (b) connected + n−1 edges ⇔ (c) acyclic + n−1 edges ⇔ (d) unique path between any pair. Part (d): the new edge xy plus the unique x–y path is the only cycle.
2. What exactly is L(v) in Prim, and how does it differ from L(v) in Dijkstra?Prim: the weight of the cheapest single edge from v to the current tree. Dijkstra: the length of the shortest s→v path whose vertices, apart from v, all lie in T, so L(v′) + w(v′v).
3. Kruskal examines edge e = xy. How does it decide whether to accept it, and which data structure makes that fast?Accept iff x and y are in different components (find(x) ≠ find(y)), then union them. Union–find gives O(m log n) overall.
4. Give the one-sentence exchange argument used for MSTs.If an MST T* doesn't contain your greedy edge e, then T* + e has a cycle containing another edge e′ with w(e′) ≥ w(e), and T* + e − e′ is an MST that does contain e.
5. Draw a 4-vertex digraph on which Dijkstra gives a wrong answer.s→u 2, u→x 3, x→v −6, s→v 1. Dijkstra finalises v at 1, but s,u,x,v has weight −1.
6. Write the Floyd–Warshall recurrence and say what dk(u,v) means.dk(u,v) = min{dk−1(u,v), dk−1(u,k) + dk−1(k,v)}. It is the shortest u→v distance using only 1..k as intermediate vertices. O(n³).
7. What two conditions make a flow feasible? How is val(f) defined?Capacity 0 ≤ f(e) ≤ c(e), and conservation f⁺(v) = f⁻(v) for v ≠ s,t. val(f) = f⁻(t) − f⁺(t).
8. Leeway on a backward edge equals…?…the flow f(e) on it (you can cancel at most what's there). On a forward edge it is c(e) − f(e).
9. State weak duality and Max-Flow Min-Cut. Which one is easy?Weak: val(f) ≤ cap(S,T) for any feasible f and any cut (easy, since all flow must cross the cut). MFMC: max val = min cap (proved by the labelling algorithm stopping with a tight cut).
10. Build G′ for a bipartite graph. Why is the resulting flow a matching?Direct V₁→V₂, add s→V₁ and V₂→t, set all capacities to 1. Each V₁ vertex receives at most 1 unit, so conservation lets it send along at most one middle edge (and symmetrically for V₂).
11. Why is Ford–Fulkerson's O(nmU) not "polynomial"?U is stored in log U bits, so running time linear in U is exponential in the input length.
12. Berge's theorem?M is maximum ⇔ G has no M-augmenting path.