10: Greedy Algorithms
Greedy algorithms build solutions incrementally, making locally optimal choices at each step. The challenge: proving these myopic decisions lead to globally optimal solutions.
The Greedy Paradigm
Goal: Find a solution that maximizes/minimizes an objective function .
Challenge: The space of possible solutions is exponentially large.
Insight: The solution is composed of several parts (e.g., is a set or sequence).
Approach:
- Compute one part at a time
- Select the next part “greedily” for immediate benefit
- Prove this yields an optimal solution despite no foresight
Greedy algorithms typically run in polynomial time. The hard part is proving optimality.
Interval Scheduling
Problem Definition
- Job starts at time and finishes at time
- Two jobs and are compatible if and don’t overlap
- Goal: Find maximum-size subset of mutually compatible jobs
Greedy Template
Consider jobs in some “natural” order. Take a job if it’s compatible with those already chosen.
Possible orderings:
- Earliest start time: ascending order of
- Earliest finish time: ascending order of
- Shortest interval: ascending order of
- Fewest conflicts: ascending order of (number of conflicting jobs)
Only earliest finish time (EFT) works. The others have counterexamples:
- Earliest start time fails when one long job starts first
- Shortest interval fails when a short job blocks two longer compatible jobs
- Fewest conflicts fails in certain symmetric configurations
Algorithm: Earliest Finish Time (EFT)
Sort jobs by finish time: f_1 ≤ f_2 ≤ ... ≤ f_n
S ← ∅
for j = 1 to n:
if job j is compatible with S:
S ← S ∪ {j}
return SRunning time:
- Sorting:
- Compatibility check: per job (just check if where is the last added job)
Proof of Optimality by Contradiction
- Suppose greedy is not optimal
- Let greedy select jobs (sorted by finish time)
- Consider an optimal solution that matches greedy for as many indices as possible
- for the greatest possible
- Both and are compatible with the previous selection
- Since greedy chose by EFT:
- Replace with in the optimal solution:
- Still feasible: for
- Still optimal: same number of jobs
- But matches greedy for indices — contradiction!
Proof of Optimality by Induction
Let be the subset picked by greedy after considering the first jobs.
Definition: is promising if such that is optimal.
Claim: For all , is promising.
Base case: is promising (any optimal solution extends it).
Induction step: Assume is promising with optimal extension .
Case 1: Greedy didn’t select job (conflicts with )
- Since , job also conflicts with
- So also extends
Case 2: Greedy selected job , so
- Let be the earliest job in
- Replace with in to get
- is still feasible (since ) and optimal
- extends ∎
Interval Partitioning
Problem Definition
- Job starts at time and finishes at time
- Goal: Partition jobs into fewest groups such that jobs in each group are mutually compatible
Think of scheduling lectures into classrooms.
Algorithm: Earliest Start Time (EST)
Sort lectures by start time: s_1 ≤ s_2 ≤ ... ≤ s_n
d ← 0 (number of classrooms)
for j = 1 to n:
if lecture j is compatible with some classroom k:
Schedule lecture j in classroom k
else:
Allocate new classroom d+1
Schedule lecture j in classroom d+1
d ← d + 1
return scheduleImplementation with priority queue:
- Store classrooms in a min-heap keyed by latest finish time
- Check if minimum key
- priority queue operations → time
Proof of Optimality
Definition: The depth is the maximum number of lectures running at any time.
Lower bound:
Claim: Greedy uses exactly depth classrooms.
Proof:
- Let = number of classrooms used by greedy
- Classroom was opened because lecture conflicted with all existing classrooms
- All lectures end after
- Since we sorted by start time, they all start at or before
- At time , we have mutually overlapping lectures
- Therefore, ∎
Since , greedy is optimal.
Minimizing Lateness
Problem Definition
- Single machine processes jobs
- Job requires time and is due at
- If scheduled at , finishes at
- Lateness:
- Goal: Minimize maximum lateness
Algorithm: Earliest Deadline First (EDF)
Sort jobs by deadline: d_1 ≤ d_2 ≤ ... ≤ d_n
t ← 0
for j = 1 to n:
Assign job j to interval [t, t + t_j]
s_j ← t
f_j ← t + t_j
t ← t + t_j
return intervalsCounterexamples for other orderings:
Shortest processing time first:
| Job | ||
|---|---|---|
| 1 | 1 | 100 |
| 2 | 10 | 10 |
Processing job 1 first delays job 2 unnecessarily.
Smallest slack first:
| Job | ||
|---|---|---|
| 1 | 1 | 2 |
| 2 | 10 | 10 |
Slack : job 1 has slack 1, job 2 has slack 0. But doing job 2 first causes lateness.
Proof of Optimality
Key observations:
- There is an optimal schedule with no idle time
- EDF has no idle time
- An inversion is a pair where but is scheduled before
- EDF has no inversions
- If a schedule has inversions, it has an adjacent inverted pair
Lemma: Swapping adjacent inverted jobs doesn’t increase lateness but reduces inversions by 1.
Proof:
- Let and denote lateness before and after swap
- For : (finish times unchanged)
- For job : (moved earlier)
- For job : (using from the inversion)
- Therefore:
Proof by contradiction:
- Suppose EDF is not optimal
- Take optimal schedule with fewest inversions (no idle time WLOG)
- Since EDF is not optimal, has at least one inversion
- By observation 5, it has an adjacent inversion
- Swapping maintains optimality but reduces inversions — contradiction! ∎
Proof by reverse induction:
Claim: For each , there exists an optimal schedule with at most inversions.
- Base case : trivial
- Induction: If claim holds for , take optimal with inversions
- If inversions, done
- If exactly inversions, swap adjacent inverted pair → inversions
- Claim for proves EDF optimality ∎
Huffman Coding (Lossless Compression)
Problem Definition
- Document uses distinct symbols with frequencies
- Naive encoding: bits per symbol
- Goal: Find prefix-free encoding minimizing
Prefix-free encoding: No codeword is a prefix of another. This enables unambiguous decoding.
Key insight: Prefix-free encodings correspond to binary trees where symbols are leaves.
Huffman’s Algorithm
Build priority queue with (symbol, frequency) pairs
while |queue| ≥ 2:
(x, w_x) ← extract-min(queue)
(y, w_y) ← extract-min(queue)
Create new node z with children x and y
Insert (z, w_x + w_y) into queue
return treeRunning time:
Can be made if symbols are pre-sorted by frequency (using two queues).
Example
Frequencies:
Steps:
- Merge (5) and (10) → node with weight 15
- Merge (11) and (12) → node with weight 23
- Merge 15 and (20) → node with weight 35
- Merge 23 and 35 → node with weight 58
- Merge (42) and 58 → root with weight 100
Result:
Higher frequency symbols get shorter codes.
Proof of Optimality
Induction on number of symbols .
Base case: . Both 1-bit encodings are optimal.
Lemma 1: If , then in any optimal tree.
Proof: If and , swapping reduces total length:
Lemma 2: There exists an optimal tree where the two lowest-frequency symbols and are siblings.
Proof:
- Take any optimal tree
- If doesn’t have longest encoding, swap with one that does (no cost increase by Lemma 1)
- must have a sibling (otherwise, could shorten its code)
- If sibling isn’t , swap with (no cost increase)
Induction step:
- Let be the two lowest-frequency symbols Huffman merges into
- Let be Huffman’s tree, be optimal tree where are siblings
- Let and treat as one symbol with weight
- By induction:
- Therefore ∎
Summary of Proof Techniques
| Problem | Algorithm | Proof Technique |
|---|---|---|
| Interval Scheduling | Earliest Finish Time | Contradiction/Induction (exchange argument) |
| Interval Partitioning | Earliest Start Time | Lower bound matching |
| Minimizing Lateness | Earliest Deadline First | Inversion counting |
| Huffman Coding | Merge lowest frequencies | Induction on problem size |
Common pattern: Show that any optimal solution can be transformed into the greedy solution without increasing cost.
Other Classic Greedy Algorithms
- Dijkstra’s algorithm: Single-source shortest paths
- Kruskal’s algorithm: Minimum spanning tree (sort edges, add if no cycle)
- Prim’s algorithm: Minimum spanning tree (grow tree from source)