Greedy strategy & activity selection
The greedy-choice property and optimal substructure, proved by an exchange argument, applied to activity selection.
What makes an algorithm greedy
A greedy algorithm makes the choice that looks best *right now* and never reconsiders it. It commits to a locally optimal choice before solving any subproblem, then recurses on the one subproblem that remains. This is the opposite of dynamic programming, which solves subproblems *first* and only then chooses. Greedy is therefore top-down and DP is bottom-up; greedy considers exactly one choice per step where DP considers all of them.
Greedy does not always work. When it does, the problem has two properties:
- Greedy-choice property — a globally optimal solution can be built by making locally optimal (greedy) choices. The greedy choice may depend on choices made so far, but not on the solutions to future subproblems.
- Optimal substructure — an optimal solution to the problem contains optimal solutions to its subproblems. (DP needs this too; greedy uses it after assuming the greedy choice is already made.)
The activity-selection problem
You are given $n$ activities, each with a start time $s_i$ and a finish time $f_i$ (the activity occupies the half-open interval $[s_i, f_i)$). Two activities are compatible if their intervals do not overlap. The goal is to select a maximum-size set of mutually compatible activities — think of scheduling the most events possible in one lecture hall.
The greedy choice: sort the activities by finish time, then always take the *next* activity whose start time is at or after the finish time of the last one you took. Taking the earliest-finishing compatible activity leaves the resource free as soon as possible, maximizing room for the rest.
Worked example. With 11 activities sorted by finish time (CLRS Fig. 15.1):
$$\begin{array}{c|ccccccccccc} i & 1 & 2 & 3 & 4 & 5 & 6 & 7 & 8 & 9 & 10 & 11\\\hline s_i & 1 & 3 & 0 & 5 & 3 & 5 & 6 & 8 & 8 & 2 & 12\\ f_i & 4 & 5 & 6 & 7 & 9 & 9 & 10 & 11 & 12 & 14 & 16 \end{array}$$
Take $a_1$ (finishes at 4). The next compatible one is $a_4$ (starts at $5 \ge 4$, finishes at 7). Then $a_8$ (starts at $8 \ge 7$, finishes at 11). Then $a_{11}$ (starts at $12 \ge 11$). Result: $\{a_1, a_4, a_8, a_{11}\}$ — four activities, which is optimal.
Why earliest-finish is safe (Theorem 15.1)
The correctness rests on an exchange argument, the canonical proof for the greedy-choice property. Let $a_m$ be the earliest-finishing activity in a subproblem, and let $A$ be *any* maximum-size compatible set for that subproblem. Let $a_j$ be the earliest-finishing activity in $A$. If $a_j = a_m$, we are done. Otherwise build $A' = (A - \{a_j\}) \cup \{a_m\}$. Because $f_m \le f_j$, swapping $a_j$ out for $a_m$ keeps every later activity compatible, so $A'$ is still valid and $|A'| = |A|$. Thus a maximum-size solution containing the greedy choice exists. ∎
After the $O(n \lg n)$ sort, the selection loop is $\Theta(n)$: each activity is examined once. Contrast this with the $\Theta(n^2)$ DP recurrence $c[i,j] = \max_k \{c[i,k] + c[k,j] + 1\}$ that the greedy choice collapses into a single $O(1)$ choice per step.