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.
- Read the map first (2 min). There are six problems, three design techniques, and one proof pattern that keeps coming back.
- 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).
- 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.
- Keep the "carry into the lecture" questions in mind. They are what the proofs in the notes are really answering.
- Do the self-test the next day. Retrieval practice after a gap is what moves this into long-term memory.
- 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 said | What 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 said | What 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.
- "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.
- 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.
- 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.
- 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.
- 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.
- 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.
- Connected is a ∀∃ statement: for every pair of vertices there exists a path. There may be many paths; you only need one.
- 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.
- 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.
- Forest: every connected component is a tree (equivalently, it has no cycle).
- "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:
- State the problem precisely: input, output, and any restrictions (e.g. w ≥ 0, connected, no negative closed walks).
- Write the pseudocode with the notes' line numbers. The proofs refer to lines ("by line 5…").
- Trace it on a small graph and produce the iteration table the notes use.
- Give the proof skeleton: what is being inducted on, what the invariant or claim is, and where the key inequality comes from.
- 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 covered | Where 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 |
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
| Problem | Input | Algorithm | Technique | Time |
|---|---|---|---|---|
| Minimum weight spanning tree | connected graph, w: E→ℕ | Prim, Kruskal | greedy | O(m + n log n), O(m log n) |
| Single-source shortest paths | digraph, w: E→ℕ (≥ 0) | Dijkstra | greedy | O(m + n log n) |
| All-pairs shortest paths | digraph, w: E→ℤ, no negative closed walk | Floyd–Warshall | dynamic programming | O(n³) |
| Maximum flow | network, c: E→ℕ, source s, sink t | Ford–Fulkerson | iterative improvement | O(nmU) |
| Max matching, bipartite | bipartite graph | reduce to max flow | reduction | O(nm) |
| Max matching, general optional | any graph | Edmonds' blossom | augmenting paths | O(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 ask | Lemma 2.2 | What 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 proof | Why 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
- Lemma 2.1 says a cycle edge is "safe" to delete. The MST proofs turn this around: adding an edge to a tree creates exactly one cycle, and removing another edge of that cycle keeps a tree. Look for this in the Prim proof (T* + e − e′).
- The extremal choice here ("fewest edges") comes back in Kruskal's proof ("the MST with the most edges in common with T").
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
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
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
- Greedy fails for many problems. What property of spanning trees makes it safe here? (Hint: the swap e ↔ e′.)
- Prim and Kruskal produced the same tree above. Must they always? What if weights are tied?
- Why does the Prim proof need the cycle to cross the boundary VT | V∖VT twice?
- Kruskal's "is T + e acyclic?" can be answered with BFS or DFS. Why is that too slow, and what does union–find buy you?
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
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.
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
- In Dijkstra, at the moment v′ is chosen, why can no future discovery ever lower L(v′)?
- Where exactly does the Dijkstra proof use w ≥ 0? Find the line in the animation above where the negative edge "arrives too late".
- In Floyd–Warshall, why must k be the outermost loop? What goes wrong if you loop over u first?
- How would a negative cycle show up in the final matrix? (Look at the diagonal.)
- Why is the longest path problem hard (NP-complete) when the shortest path problem is easy?
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:
- capacity: 0 ≤ f(e) ≤ c(e) on every edge, and
- conservation: flow in = flow out, f⁻(v) = f⁺(v), at every v ≠ s,t.
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)
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
- In the animation (level 2), the path s→x←v→t uses a backward edge. Physically, what happens to the unit of flow that was on vx?
- Why does the cut capacity count only S→T edges and not T→S edges?
- Where does the proof use that capacities are integers? What could go wrong with irrational capacities?
- Weak duality gives you a way to certify optimality without trusting the algorithm. Why is that valuable (e.g. when checking GenAI output)?
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
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
- Why must every capacity be 1, including on the s- and t-edges? What would capacity 2 on su allow?
- Why does "Ford–Fulkerson from the zero flow gives integer flows" matter for this reduction?
- Relate each augmentation to the matching: one more matched pair each time, and backward edges = swapping partners.
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.
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.R1 · Number sets and ∞
| Symbol | Meaning | In the notes |
|---|---|---|
| ℕ | natural numbers {0, 1, 2, …}. Here 0 is included, since capacities and flows may be 0. | w : E → ℕ, c : E → ℕ, f : E → ℕ |
| ℤ | integers {…, −2, −1, 0, 1, 2, …} | Floyd–Warshall allows w : E → ℤ (negative edges) |
| ℝ | real numbers | not needed here |
| ∞ | not a number, but a convention: x < ∞ for every number x, and ∞ + x = ∞ | w(uv) = ∞ if uv ∉ E; dist(u,v) = ∞ if there is no path |
| {1, …, k} | the integers from 1 to k (empty if k = 0) | "for every i ∈ {1,…,k}" |
R2 · Sets
| Notation | Read as | Meaning / example |
|---|---|---|
| {1, 2, 3} | "the set containing 1, 2, 3" | Order and repetition don't matter: {1,2} = {2,1} = {1,1,2}. That's why the edge {u,v} = {v,u}. |
| x ∈ A, x ∉ A | "x is (not) an element of A" | v ∈ V(G), uv ∈ E(G) |
| A ⊆ B | "A is a subset of B" | every element of A is in B: ∀x (x ∈ A ⇒ x ∈ B). E(H) ⊆ E(G). |
| A ⊂ B (also ⊊) | "A is a proper subset of B" | A ⊆ B and A ≠ B. Some texts use ⊂ to mean ⊆, so check the context. |
| A = B | "A equals B" | Proved by double inclusion: A ⊆ B and B ⊆ A. |
| ∅ | "the empty set" | ET ← ∅ (start with no edges). Note ∅ ⊆ A for every A, and |{∅}| = 1. |
| |A| | "the size (cardinality) of A" | |V| = n, |E| = m, |VT| in the Prim proof |
| A ∪ B | "A union B" | the elements in A or B (or both). ET ← ET ∪ {e}. |
| A ∩ B | "A intersect B" | the elements in both |
| A ∖ B | "A minus B" | the elements in A but not in B. V ∖ VT = vertices not yet in the tree. |
| A ∩ B = ∅ | "A and B are disjoint" | |
| partition of V into S, T | S ∩ T = ∅ and S ∪ T = V. This is a source/sink cut [S,T]. |
E ⊆ { X ⊆ V : |X| = 2 }.
Wrong: "v ⊆ V", "{v} ∈ V", "uv ⊆ E". Right: "v ∈ V", "{v} ⊆ V", "{uv} ⊆ E" or "uv ∈ E".
R3 · Set-builder notation {x ∈ A | P(x)}
{ u ∈ V(G) | uv ∈ E(G) }
─┬─ ──┬── ┬ ────┬────
│ │ │ └── condition: which elements to keep
│ │ └── "such that" ( | and : mean the same thing )
│ └── where to look (the domain)
└── the variable (a dummy name)
read: "the set of all u in V(G) such that uv is an edge of G" = N_G(v)
Two forms. Filter: {x ∈ A | P(x)} keeps the elements of A that satisfy P. Image: {f(x) : x ∈ A} computes f(x) for each x, e.g. {w(e) : e ∈ E} is the set of all edge weights.
Bound vs free variables. In {u ∈ V | uv ∈ E}, u is a dummy (bound) variable, so renaming it to x changes nothing. v is free: it must already be fixed outside ("for a vertex v…"), and the set depends on it.
| From the notes | Read as |
|---|---|
| NG(v) = {u ∈ V(G) | uv ∈ E(G)} | the vertices adjacent to v |
| {xy ∈ E(G) | x, y ∈ U} | the edges with both ends in U, i.e. E(G[U]) |
| {e1, …, e|E|} | E listed with indices (Kruskal, after sorting) |
| {uv : u ∈ V₁, v ∈ V₂, f(uv) = 1} | the middle edges carrying flow, i.e. the matching (Thm 5.1) |
| min{L(v) : v ∈ V ∖ VT} | the smallest label among vertices outside the tree |
| Σ{vu ∈ E : u ∈ V} f(vu) | f⁺(v): the total flow on edges leaving v |
R4 · Ordered pairs, sequences, indices
- (u, v) is an ordered pair: (u,v) ≠ (v,u) unless u = v. Compare the set {u,v} = {v,u}. Digraph arcs are ordered pairs; graph edges are sets.
- A × B = {(a,b) : a ∈ A, b ∈ B}, the Cartesian product. A digraph's arc set satisfies A ⊆ V × V.
- G = (V, E) is itself an ordered pair: a graph is "a pair of sets".
- Sequences with indices: v0, v1, …, vk has k+1 terms. "For every i ∈ {1,…,k}, ei is incident with vi−1 and vi." Always check where the index starts and stops, since off-by-one mistakes are the classic slip.
- Relabelling: "Relabel E = {e1,…,e|E|} so that w(e1) ≤ … ≤ w(e|E|)" just means sort the edges and name them in that order.
R5 · Functions
- f : A → B is read "f is a function from A to B". A is the domain and B the codomain. It assigns exactly one f(a) ∈ B to every a ∈ A.
- w : E → ℕ: every edge gets one natural-number weight. c (capacity) and f (flow) are also functions E → ℕ.
- Labels are functions on vertices: L : V → ℕ ∪ {∞} in Prim and Dijkstra. "L(v) ← …" in pseudocode means "update the value of L at v".
- Two-argument functions: dist : V × V → ℕ ∪ {∞}, and dk(u,v) in Floyd–Warshall.
- Extending a function to a set: w(T) := Σe∈E(T) w(e) is a new definition that reuses the name w. You'll see this "overloading" often.
- ← vs = vs := "x ← y" (pseudocode) means assign y to x. "=" is a claim that two things are equal. ":=" means "is defined as".
R6 · Sums, min, max
Σ w(e) "the sum, over all edges e in E(T), of w(e)"
e∈E(T)
Σ d(v) = 2m "the sum of the degrees is twice the number of edges" (handshake lemma)
v∈V
Σ_{i=1}^{k} w(v_{i−1} v_i) "sum for i from 1 to k" = weight of the path v_0,…,v_k
- The index under Σ is a dummy variable. The condition under Σ filters which terms to include, like set-builder notation.
- An empty sum = 0. By convention, min ∅ = ∞, which is why dist(u,v) = ∞ when no path exists.
- "Find x for which L(x) = min{L(v) : v ∈ V ∖ VT}" picks an element that achieves the minimum (an "argmin"). It may not be unique, and then any choice works.
- Weak vs strict: ≤ allows equality and < doesn't. Proofs often hinge on this (e.g. w(e) ≤ w(e′) in the Prim proof).
R7 · Propositional logic: ¬ ∧ ∨ ⇒ ⇔
| Symbol | Read | True when |
|---|---|---|
| ¬P | not P | P is false |
| P ∧ Q | P and Q | both |
| P ∨ Q | P or Q | at least one (inclusive "or") |
| P ⇒ Q | P implies Q | it is not the case that P is true and Q false |
| P ⇔ Q | P if and only if Q (iff) | P and Q have the same truth value |
| P | Q | P ⇒ Q |
|---|---|---|
| T | T | T |
| T | F | F |
| F | T | T |
| F | F | T |
If P is false, then P ⇒ Q is true ("vacuously").
Ways of saying P ⇒ Q (all the same)
if P then Q · P implies Q · Q if P · P only if Q · P is sufficient for Q · Q is necessary for P · whenever P, Q
Related statements
| Form | Equivalent to P ⇒ Q? | Lemma 2.1 example (G connected) | |
|---|---|---|---|
| original | P ⇒ Q | e lies on a cycle ⇒ e is not a cut-edge | |
| contrapositive | ¬Q ⇒ ¬P | yes, always | e is a cut-edge ⇒ e lies on no cycle |
| converse | Q ⇒ P | no (a separate claim) | e is not a cut-edge ⇒ e lies on a cycle |
| inverse | ¬P ⇒ ¬Q | no (it is equivalent to the converse) | e lies on no cycle ⇒ e is a cut-edge |
| negation | ¬(P ⇒ Q) ≡ P ∧ ¬Q | the opposite | e lies on a cycle and e is a cut-edge |
Lemma 2.1 is an iff: both the original and the converse hold. That's why the notes use ⇔, and why its proof needs two directions, (⇒) and (⇐).
Laws you use without noticing
- P ⇔ Q ≡ (P ⇒ Q) ∧ (Q ⇒ P)
- P ⇒ Q ≡ ¬P ∨ Q
- De Morgan: ¬(P ∧ Q) ≡ ¬P ∨ ¬Q, and ¬(P ∨ Q) ≡ ¬P ∧ ¬Q
- ¬¬P ≡ P
- Theorem 2.3 says "(a), (b), (c), (d) are equivalent". The usual way to prove this is a cycle of implications, (a)⇒(b)⇒(c)⇒(d)⇒(a), and "(a) ⇒ (d)" in a proof quotes one link of that cycle.
R8 · Quantifiers: ∀ (upside-down A) and ∃ (backwards E)
| Symbol | Read | Meaning |
|---|---|---|
| ∀x ∈ A: P(x) | "for all / for every / for each x in A, P(x)" | no exceptions. Same as ∀x (x ∈ A ⇒ P(x)). |
| ∃x ∈ A: P(x) | "there exists (there is) an x in A such that P(x)" | at least one. Same as ∃x (x ∈ A ∧ P(x)). |
| ∃!x: P(x) | "there exists a unique x" | exactly one: existence plus uniqueness. Theorem 2.3(d) says there is "exactly one path". |
Order matters
∀v ∈ V ∃u ∈ V: uv ∈ E means "every vertex has a neighbour" (u may depend on v).
∃u ∈ V ∀v ∈ V∖{u}: uv ∈ E means "one vertex is adjacent to all the others". This is much stronger.
Connected is ∀u,v ∃ a (u,v)-path. The path may differ for each pair.
Negating: flip each quantifier, then negate the inside
¬ ∀x P(x) ≡ ∃x ¬P(x) ¬ ∃x P(x) ≡ ∀x ¬P(x) "G is connected" ∀u,v ∈ V ∃ (u,v)-path "G is NOT connected" ∃u,v ∈ V such that there is NO (u,v)-path
Hidden quantifiers and how a proof handles them
- "A tree on n vertices has n−1 edges" has a hidden ∀: it holds for every tree.
- To prove ∀x P(x): write "Let x be arbitrary" and prove P(x) using only what you're given. A drawing of one example is not enough (her point in lecture 1).
- To prove ∃x P(x): construct or exhibit one x. "Since G is connected, there is a (u,v)-path P" uses an ∃ you already know.
- To disprove ∀: one counterexample is enough. To disprove ∃: you need a proof for all.
- Vacuous truth: "∀v ∈ ∅: …" is automatically true. For example, when T = V the loop "for all v ∉ T" does nothing.
R9 · Proof methods, and where each appears in the notes
| Method | Shape | In the notes |
|---|---|---|
| Direct | Assume P. Derive Q step by step. | Lemma 2.2 (⇒), Weak duality (Cor. 4.3), Lemma 4.1 |
| Contrapositive | To prove P ⇒ Q: assume ¬Q, derive ¬P. | often used implicitly |
| Contradiction | Assume the statement is false and derive something impossible. "This contradicts…" □ | Lemma 2.2 (⇐), Kruskal (Thm 2.5), Dijkstra key step, Thm 5.1 |
| Extremal choice | "Choose X with the fewest edges / most edges in common / …". If X had the bad property, build a better X′, contradicting the choice. | Lemma 2.2 (fewest edges), Kruskal (T* with most edges in common with T) |
| Induction | Base case, then the induction hypothesis (IH) "assume true for k", then the step "prove it for k+1". | Prim (on |VT|), Dijkstra (on |T|), Floyd–Warshall (on k) |
| Loop invariant | Induction on the number of iterations: a statement true before the loop and preserved by each pass. | Prim and Dijkstra proofs are exactly this |
| Iff | Prove (⇒) and (⇐) separately. | Lemma 2.1, Lemma 2.2, Berge |
| Cases | Split into exhaustive cases and prove each. | Lemma 4.1 (4 ways the path passes v), FW (k ∈ Q or k ∉ Q) |
| Two inequalities | Show a ≤ b and b ≤ a, so a = b. | Floyd–Warshall, Max-Flow Min-Cut |
| Exchange argument | Swap one piece of an optimal solution for yours and show it's no worse. | Prim, Kruskal (T* + e − e′) |
| Counterexample | Disprove a ∀ with one specific case. | "Dijkstra fails with negative edges" example |
| Reduction | Transform problem A into problem B that you can already solve. | Bipartite matching → max flow |
INDUCTION TEMPLATE Claim: for every n ≥ n₀, S(n). Base case (n = n₀): … so S(n₀) holds. Induction hypothesis: assume S(k) holds for some k ≥ n₀. (strong: for all n₀ ≤ j ≤ k) Induction step: we show S(k+1). … by the induction hypothesis … hence S(k+1). By induction, S(n) holds for all n ≥ n₀. □
R10 · Proof language (fixed phrases)
| Let … | introduce and name an object: "Let e ∈ E(C)." "Let G be a connected graph." |
| Suppose / Assume … | start a case, a contradiction, or an IH |
| Since A, B. / By Lemma X, B. | every step names its reason |
| So / Hence / Therefore / Thus / It follows that | conclusions |
| We argue by contradiction. | announce the method before using it |
| Claim 1: … Proof of Claim 1: … | break a long proof into parts (as in the Prim proof) |
| This contradicts our choice of T. | closes an extremal-choice argument |
| as desired / as required | you've reached the goal |
| □ | end of proof |
Avoid "clearly" and "obviously" unless it really is one line. Avoid "it" when two objects are in play: name them. Don't start using a symbol you haven't introduced.
R11 · Words that have precise meanings
| Word | Precise meaning |
|---|---|
| definition / lemma / theorem / corollary / claim | A definition names a concept. A lemma is a helper result, a theorem a main result, a corollary follows quickly from a previous result, and a claim is a sub-step inside a proof. |
| maximal vs maximum | Maximal: nothing can be added (inclusion-wise; a component is maximal). Maximum: the largest size possible (a maximum matching). Every maximum matching is maximal, but not every maximal one is maximum! |
| minimal vs minimum | The same distinction: nothing can be removed, vs smallest possible value (minimum weight spanning tree). |
| inclusion-wise | compared by ⊆, not by size |
| non-decreasing vs increasing | a ≤ b ≤ c (ties allowed; Kruskal's sort) vs a < b < c |
| non-negative vs positive | ≥ 0 vs > 0 |
| a shortest path vs the distance | There may be several shortest paths ("a"), but dist(u,v) is a single number ("the"). |
| distinct | pairwise different |
| unique / exactly one / at least one / at most one | ∃! / ∃! / ∃ / "if two, they're equal" |
| arbitrary | any one, with nothing special assumed (sets up a ∀ proof) |
| well-defined | the definition really gives exactly one value |
| w.l.o.g. | "without loss of generality": the other cases are the same by symmetry or renaming |
| i.e. vs e.g. | "that is" (restates exactly) vs "for example" |
| s.t. · resp. · iff | such that · respectively · if and only if |
| trivial | immediate from the definitions (use sparingly) |
R12 · Big-O and running time
f(n) = O(g(n)) means f grows no faster than g, up to a constant: ∃c > 0 ∃n₀ ∀n ≥ n₀: f(n) ≤ c·g(n).
In practice, drop constants and lower-order terms: 3n² + 5n + 7 = O(n²).
Growth order: 1 < log n < n < n log n < n² < n³ < 2ⁿ. The notes' algorithms sit between n log n and n³.
- n = |V|, m = |E| throughout. In a simple graph m ≤ n(n−1)/2, so m = O(n²) and log m = O(log n). That's why O(m log m) = O(m log n) for Kruskal.
- Dense graph: m is about n². Sparse: m is about n. O(m + n log n) is roughly n² for dense graphs and n log n for sparse ones.
- Σv d(v) = 2m is the trick behind "the inner loop runs d(x) times, so O(m) in total" (Prim, Dijkstra).
- Polynomial in the input length: numbers are stored in binary, so a capacity U takes about log U bits. O(nmU) is exponential in the input length, while O(nm log U) is polynomial.
- Amortized O(log n): averaged over a sequence of operations, as in the Fibonacci heap. You'll meet it later in the module.