|
| 1 | +## What are greedy algorithms? |
1 | 2 |
|
| 3 | +Greedy methods construct a solution piece by piece, always choosing the currently best-looking option according to a simple rule. The subtlety is not the rule itself but the proof that local optimality extends to global optimality. Two proof tools do most of the work: exchange arguments (you can swap an optimal solution’s first “deviation” back to the greedy choice without harm) and loop invariants (you maintain a statement that pins down exactly what your partial solution guarantees at each step). |
| 4 | + |
| 5 | +Formally, consider a finite ground set $E$, a family of feasible subsets $\mathcal{F}\subseteq 2^E$, and a weight function $w:E\to \mathbb{R}$. A generic greedy scheme orders elements of $E$ by a key $\kappa(e)$ and scans them, adding $e$ to the building solution $S$ if $S\cup\{e\}\in\mathcal{F}$. Correctness means |
| 6 | + |
| 7 | +$$ |
| 8 | +\text{Greedy}(E,\mathcal{F},w,\kappa)\in\arg\max\{\,w(S):S\in\mathcal{F}\,\}. |
| 9 | +$$ |
| 10 | + |
| 11 | +The nice, crisp setting where this always works is the theory of matroids. Outside that, correctness must be argued problem-by-problem. |
| 12 | + |
| 13 | +``` |
| 14 | +scan order: e1 e2 e3 e4 e5 ... |
| 15 | +feasible? Y N Y Y N |
| 16 | +solution S: {e1, e3, e4} |
| 17 | +``` |
| 18 | + |
| 19 | +## The greedy-choice principle and exchange arguments |
| 20 | + |
| 21 | +A problem exhibits the greedy-choice principle if there exists an optimal solution that begins with a greedy step. Once you show that, you can peel off that step and repeat on the residual subproblem. Exchange arguments are a tight way to prove it. |
| 22 | + |
| 23 | +Let $G$ be the greedy solution and $O$ an optimal solution. Suppose the first element where they differ is $g\in G$ and $o\in O$. If replacing $o$ by $g$ in $O$ keeps feasibility and does not reduce the objective, then there exists an optimal solution that agrees with greedy at that position. Repeating this swap inductively transforms $O$ into $G$ with no loss, hence greedy is optimal. |
| 24 | + |
| 25 | +Visually, you keep “pushing” the optimal solution toward the greedy one: |
| 26 | + |
| 27 | +``` |
| 28 | +O: o ? ? ? → swap o→g at first difference |
| 29 | +G: g g g g |
| 30 | +``` |
| 31 | + |
| 32 | +## Matroids |
| 33 | + |
| 34 | +Matroids capture exactly when a simple weight-ordered greedy works for all weights. |
| 35 | + |
| 36 | +A matroid is a pair $(E,\mathcal{I})$ where $\mathcal{I}\subseteq 2^E$ satisfies three axioms: non-emptiness $\varnothing\in\mathcal{I}$, heredity $A\in\mathcal{I}$ and $B\subseteq A\Rightarrow B\in\mathcal{I}$, and augmentation if $A,B\in\mathcal{I}$ with $|A|<|B|$ then there exists $x\in B\setminus A$ such that $A\cup\{x\}\in\mathcal{I}$. |
| 37 | + |
| 38 | +Given nonnegative weights $w:E\to\mathbb{R}_{\ge 0}$, the greedy algorithm that scans in order of decreasing $w$ and keeps an element whenever independence is preserved returns a maximum-weight independent set. The proof is a one-line exchange: if greedy kept $g$ and an optimal $O$ did not, augmentation in the matroid allows swapping in $g$ for some element of $O$ without losing feasibility or weight. |
| 39 | + |
| 40 | +Two takeaways rise above the formalism. When your feasibility system has an augmentation flavor, greedy tends to shine. When augmentation fails, greedy can fail spectacularly and you should be suspicious. |
| 41 | + |
| 42 | +## Loop invariants |
| 43 | + |
| 44 | +Some greedy scans are best understood with invariants that certify what your partial state already guarantees. |
| 45 | + |
| 46 | +A linear reachability scan on positions $0,1,\dots,n-1$ with “hop budgets” $a_i\ge 0$ uses the invariant |
| 47 | + |
| 48 | +$$ |
| 49 | +F_i=\max\{\, j+a_j : 0\le j\le i,\ j\le F_{j}\ \text{when processed}\,\}, |
| 50 | +$$ |
| 51 | + |
| 52 | +where $F_i$ is the furthest index known reachable after processing index $i$. If at some step $i>F_{i-1}$, progress is impossible, because every candidate that could have extended the frontier was already considered. |
| 53 | + |
| 54 | +``` |
| 55 | +indices: 0 1 2 3 4 5 |
| 56 | +a[i]: 3 1 0 2 4 1 |
| 57 | +frontier after i=0: F=3 |
| 58 | +after i=1: F=max(3,1+1)=3 |
| 59 | +after i=2: F=max(3,2+0)=3 |
| 60 | +stuck at i=4 because 4>F |
| 61 | +``` |
| 62 | + |
| 63 | +The invariant is monotone and essentially proves itself: no future step can invent a larger $j+a_j$ from a $j$ you skipped as unreachable. |
| 64 | + |
| 65 | +## Minimum spanning trees |
| 66 | + |
| 67 | +Two greedy algorithms produce minimum spanning trees in a connected weighted graph $G=(V,E,w)$. |
| 68 | + |
| 69 | +Kruskal’s rule sorts edges by nondecreasing weight and adds an edge if it connects two different components of the partial forest. Prim’s rule grows a single tree, always adding the lightest edge that leaves the current tree. Both succeed due to the cut and cycle properties. |
| 70 | + |
| 71 | +For any partition $(S,V\setminus S)$, the lightest edge crossing the cut belongs to some minimum spanning tree. For any cycle $C$, the heaviest edge on $C$ does not belong to any minimum spanning tree. The first property justifies “always add the cheapest safe edge,” while the second justifies “never add an edge that would create a cycle unless it is not the heaviest on that cycle.” |
| 72 | + |
| 73 | +A crisp exchange proves the cut property. If a minimum tree $T$ does not use the cut’s lightest edge $e$, add $e$ to $T$ to form a cycle. That cycle must cross the cut at least twice; remove a heavier cross-edge from the cycle to get a strictly cheaper spanning tree, a contradiction. |
| 74 | + |
| 75 | +``` |
| 76 | +cut S | V\S |
| 77 | + \ | / |
| 78 | + \ | / ← add the cheapest cross-edge |
| 79 | +-----\|/----- |
| 80 | +``` |
| 81 | + |
| 82 | +Union–find makes Kruskal’s rule nearly linear; a binary heap makes Prim’s rule nearly linear as well. |
| 83 | + |
| 84 | +## Shortest paths with nonnegative weights |
| 85 | + |
| 86 | +Dijkstra’s method picks an unsettled vertex with minimum tentative distance and settles it forever. The loop invariant is the heart: when a vertex $u$ is settled, its label $d(u)$ equals the true shortest-path distance $\delta(s,u)$. The proof uses nonnegativity. If there were a shorter route leaving the settled set, it would have to traverse an edge of nonnegative weight to an as-yet unsettled vertex v, which cannot reduce the label below the minimum label currently available to settle. Formally, an exchange of the “last edge that leaves the settled set” gives the contradiction. |
| 87 | + |
| 88 | +It helps to picture the labels as a wavefront expanding through the graph: |
| 89 | + |
| 90 | +``` |
| 91 | +settled: #### |
| 92 | +frontier: ..... |
| 93 | +unseen: ooooo |
| 94 | +labels grow outward like ripples in a pond |
| 95 | +``` |
| 96 | + |
| 97 | +Negative edge weights break the monotonicity that makes “settle and forget” safe. |
| 98 | + |
| 99 | +## Prefix sums and the maximum contiguous sum |
| 100 | + |
| 101 | +Consider a finite sequence $x_1,\dots,x_n$. Define prefix sums $S_0=0$ and $S_j=\sum_{k=1}^j x_k$. Any contiguous sum equals $S_j-S_i$ for some $0\le i<j$. The optimum is |
| 102 | + |
| 103 | +$$ |
| 104 | +\max_{1\le j\le n}\bigl(S_j-\min_{0\le t<j} S_t\bigr). |
| 105 | +$$ |
| 106 | + |
| 107 | +One pass that tracks the current prefix and the smallest prefix seen so far achieves the maximum. The greedy flavor is the “reset if the running sum drops too low” heuristic, which is simply the above formula written incrementally. |
| 108 | + |
| 109 | +``` |
| 110 | +S: 0 2 1 4 3 -1 2 |
| 111 | +min: 0 0 0 0 0 -1 -1 |
| 112 | +gap: 0 2 1 4 3 0 3 → optimum 4 |
| 113 | +``` |
| 114 | + |
| 115 | +When every $x_i<0$, the best segment is the largest (least negative) single element, which appears automatically since the minimum prefix keeps descending. |
| 116 | + |
| 117 | +## Scheduling themes |
| 118 | + |
| 119 | +Two fundamental one-line rules show up over and over. |
| 120 | + |
| 121 | +Choosing as many compatible time intervals as possible is achieved by sorting by finishing time and repeatedly keeping the earliest finisher that does not conflict with what you already kept. An exchange argument makes it airtight: whenever an optimal schedule picks a later finisher as its next meeting, swapping it for the earlier finisher cannot reduce the pool of future compatible meetings because ending earlier never hurts. |
| 122 | + |
| 123 | +Minimizing maximum lateness for jobs with equal processing times is achieved by ordering by nondecreasing deadlines. If two adjacent jobs $i$ and $j$ disobey this order with $d_i>d_j$, swapping them does not increase any lateness and strictly helps one of them; repeatedly fixing inversions yields the sorted order with no worse objective. |
| 124 | + |
| 125 | +``` |
| 126 | +time → |
| 127 | +kept: [---) [--) [----) [---) |
| 128 | +others: [-----) [------) [--------) |
| 129 | +ending earlier opens more future room |
| 130 | +``` |
| 131 | + |
| 132 | +Weighted versions of these problems typically need dynamic programming rather than greedy rules. |
| 133 | + |
| 134 | +## Huffman coding |
| 135 | + |
| 136 | +Given symbol frequencies $f_i>0$ with $\sum_i f_i=1$, a prefix code assigns codeword lengths $L_i$ satisfying the Kraft inequality $\sum_i 2^{-L_i}\le 1$. The expected codeword length is |
| 137 | + |
| 138 | +$$ |
| 139 | +\mathbb{E}[L]=\sum_i f_i L_i. |
| 140 | +$$ |
| 141 | + |
| 142 | +Huffman’s algorithm repeatedly merges the two least frequent symbols. The exchange idea is simple. In an optimal tree, the two deepest leaves must be siblings and must be the two least frequent symbols; otherwise, swapping their positions with the two least frequent decreases expected length by at least $f_{\text{heavy}}-f_{\text{light}}>0$. Merging these two leaves into a single pseudo-symbol of frequency $f_a+f_b$ reduces the problem size while preserving optimality, leading to optimality by induction. |
| 143 | + |
| 144 | +The code tree literally grows from the bottom: |
| 145 | + |
| 146 | +``` |
| 147 | + * |
| 148 | + / \ |
| 149 | + * c |
| 150 | + / \ |
| 151 | + a b merge a,b first if f_a ≤ f_b ≤ f_c ≤ ... |
| 152 | +``` |
| 153 | + |
| 154 | +The cost identity $\mathbb{E}[L]=\sum_{\text{internal nodes}} \text{weight}$ turns the greedy step into a visible decrement of objective value at every merge. |
| 155 | + |
| 156 | +## When greedy fails (and how to quantify “not too bad”) |
| 157 | + |
| 158 | +The $0\text{–}1$ knapsack with arbitrary weights defeats the obvious density-based rule. A small, dense item can block space needed for a medium-density item that pairs perfectly with a third, leading to a globally superior pack. Weighted interval scheduling similarly breaks the “earliest finish” rule; taking a long, heavy meeting can beat two short light ones that finish earlier. |
| 159 | + |
| 160 | +Approximation guarantees rescue several hard problems with principled greedy performance. For set cover on a universe $U$ with $|U|=n$, the greedy rule that repeatedly picks the set covering the largest number of uncovered elements achieves an $H_n$ approximation: |
| 161 | + |
| 162 | +$$ |
| 163 | +\text{cost}_{\text{greedy}} \le H_n\cdot \text{OPT},\qquad H_n=\sum_{k=1}^n \frac{1}{k}\le \ln n+1. |
| 164 | +$$ |
| 165 | + |
| 166 | +A tight charging argument proves it: each time you cover new elements, charge them equally; no element is charged more than the harmonic sum relative to the optimum’s coverage. |
| 167 | + |
| 168 | +Maximizing a nondecreasing submodular set function $f:2^E\to\mathbb{R}_{\ge 0}$ under a cardinality constraint $|S|\le k$ is a crown jewel. Submodularity means diminishing returns: |
| 169 | + |
| 170 | +$$ |
| 171 | +A\subseteq B,\ x\notin B \ \Rightarrow\ f(A\cup\{x\})-f(A)\ \ge\ f(B\cup\{x\})-f(B). |
| 172 | +$$ |
| 173 | + |
| 174 | +The greedy algorithm that adds the element with largest marginal gain at each step satisfies the celebrated bound |
| 175 | + |
| 176 | +$$ |
| 177 | +f(S_k)\ \ge\ \Bigl(1-\frac{1}{e}\Bigr)\,f(S^\star), |
| 178 | +$$ |
| 179 | + |
| 180 | +where $S^\star$ is an optimal size-$k$ set. The proof tracks the residual gap $g_i=f(S^\star)-f(S_i)$ and shows |
| 181 | + |
| 182 | +$$ |
| 183 | +g_{i+1}\ \le\ \Bigl(1-\frac{1}{k}\Bigr)g_i, |
| 184 | +$$ |
| 185 | + |
| 186 | +hence $g_k\le e^{-k/k}g_0=e^{-1}g_0$. Diminishing returns is exactly what makes the greedy increments add up to a constant-factor slice of the unreachable optimum. |
| 187 | + |
| 188 | +## Sweep lines and event counts: a greedy counting lens |
| 189 | + |
| 190 | +Many timeline problems reduce to counting the maximum load. Turn each interval $[s,e)$ into an arrival at $s$ and a departure at $e$. Sort all events and scan from left to right, increasing a counter on arrivals and decreasing it on departures. The answer is the peak value of the counter: |
| 191 | + |
| 192 | +$$ |
| 193 | +\max_t C(t). |
| 194 | +$$ |
| 195 | + |
| 196 | +Ties are processed with departures before arrivals, which matches the half-open convention and prevents phantom conflicts when one interval ends exactly where the next begins. |
| 197 | + |
| 198 | +``` |
| 199 | +time → 1 2 3 4 5 6 7 |
| 200 | +A: [-----) |
| 201 | +B: [---) |
| 202 | +C: [-----) |
| 203 | +load: 1 2 3 2 2 1 0 |
| 204 | +peak: 3 |
| 205 | +``` |
| 206 | + |
| 207 | +While this is not “optimization by selection,” it is greedy in spirit: you never need to look back, and the loop invariant (counter equals number of currently active intervals) makes the peak exact. |
| 208 | + |
| 209 | +## Anatomy of a greedy proof |
| 210 | + |
| 211 | +It pays to recognize the tiny handful of templates that keep recurring. |
| 212 | + |
| 213 | +* Exchange template for selection: assume the first divergence between a greedy solution and an optimal solution. Show the greedy choice weakly dominates the optimal one with respect to the future, swap, and iterate. |
| 214 | +* Cut template for graphs: argue that the cheapest edge crossing a cut is always safe to add, or that the heaviest edge on any cycle is always safe to discard. |
| 215 | +* Potential or invariant template for scans: identify a monotone quantity that only moves one way; once it passes a threshold, later steps cannot undo it. |
| 216 | + |
| 217 | +These are the same ideas with different clothes. |
| 218 | + |
| 219 | +## Pitfalls, boundary choices, and complexity |
| 220 | + |
| 221 | +Monotonicity assumptions are not decoration. Dijkstra needs nonnegative edges; the proof breaks the moment a negative edge lets a later step undercut a settled label. Interval boundaries love the half-open convention $[s,e)$ to make “end at $t$, start at $t$” compatible and to simplify event-ordering in sweeps. |
| 222 | + |
| 223 | +Complexity usually splits into a sort plus a scan. Sorting $n$ items costs $O(n\log n)$. A scan with constant-time updates costs $O(n)$. Minimum spanning trees achieve $O(m\alpha(n))$ with union–find for Kruskal and $O(m\log n)$ for Prim with a heap, where $\alpha$ is the inverse Ackermann function. |
| 224 | + |
| 225 | +## A compact design checklist you can actually use |
| 226 | + |
| 227 | +* Identify a key order that seems to make future choices easier. Finishing times, smallest weights, or largest marginal gains are usual suspects. |
| 228 | +* Propose a local rule that never looks back, then write down the loop invariant that must be true if the rule is right. |
| 229 | +* Decide whether an exchange argument, a cut/cycle argument, or a potential function is the appropriate proof lens. |
| 230 | +* Stress-test the rule on a crafted counterexample. If one appears, consider whether the structure is missing a matroid-like augmentation or a monotonicity prerequisite. |
| 231 | +* If exact optimality is out of reach, look for submodularity or harmonic charging to get a clean approximation guarantee. |
0 commit comments