Skip to main content

Greedy Algorithms

Introduction

Greedy algorithms build up a solution piece-by-piece, taking locally optimal choices at each step (without reconsidering past choices). For certain problems, locally optimal choices result in a globally optimal solution; in others, they produce a near-optimal one (see approximation algorithms). In this section, we explore greedy algorithms that produce an optimal solution, as well as two styles of correctness proofs for greedy algorithms: an exchange argument or a greedy stays ahead argument.

Proof Strategies

Greedy Stays Ahead

A greedy stays ahead argument shows that your greedy solution maintains some property that is "more extreme" than any other optimal solution at every step, and that this implies optimality. The general structure is:

  1. Find a property of your greedy solution that is "more extreme" (e.g., smaller or larger) than any other solution after each step (this usually relates to your greedy criterion).
  2. Make sure that extremity of this characteristic implies optimality.
  3. Prove via induction that the greedy solution actually maintains this property at every step.
  4. Conclude that your solution is as good as optimal.
note

It is very important that you explain why your property implies optimality! A common mistake is to identify a property that greedy maintains without connecting it to the size or quality of the final solution. The property alone means nothing; you need to argue that if greedy stays ahead in this metric, it must produce a solution at least as good as any optimal solution.

Exchange Argument

Suppose that our greedy algorithm produces a solution AA. Our goal with using an exchange argument is to prove that anything in an optimal solution OO can be swapped with anything in our solution AA without losing optimality.

  1. Assume that your greedy solution and the optimal solution you choose differ in some way. (If this is not the case, then A=OA = O and we are done!).
  2. Show that it is possible to make progress, that is “exchange” elements in OO to make it more similar to your solution AA while preserving the optimality of OO.
  3. Show that this exchange progress terminates, and when it does A=OA = O where OO is optimal. Then, AA is at least as good as OO, so AA is optimal.
note

Make sure you exchange elements from OO, not AA! If you exchange elements from AA, then you change the solution that you trying to prove is optimal!

Sample Problem: Interval Scheduling

Suppose we have a machine MM that can process at most 11 job at a time. We have nn job requests, each with a start time sis_i and end time fif_i for 1in1 \le i \le n with si<fis_i < f_i. Our objective is to schedule the maximum number of non-conflicting jobs. Formally, we want to maximize the size of the set of non-conflicting jobs S[n]S \subseteq [n] that we want to schedule on MM. We say two jobs ii and jj are non-conflicting if:

  • job ii happens before job jj: sifisjfjs_i \le f_i \le s_j \le f_j
  • job jj happens before job ii: sjfjsifis_j \le f_j \le s_i \le f_i

Give an efficient algorithm that solves this problem.

Solution

To solve this problem, we want to pick the jobs with the earliest remaining finish times. This way, we leave the most remaining time for future jobs, maximizing our future options.

R = set of all jobs, A = []
while R is not empty:
pick job i in R with the earliest remaining finish time and add it to A
remove all jobs in R that conflict with i
output A

Before we prove this solution, it is a good exercise is to try and disprove bad greedy strategies. Can you find a counterexample for the following greedy approaches? For each approach, you can assume that after a job is selected, you remove all jobs that conflict with it.

  • Select the remaining job with the earliest start time.
Solution

Suppose we had 3 jobs.

  • Job 1: s1=1s_1 = 1, f1=10f_1 = 10
  • Job 2: s2=2s_2 = 2, f2=3f_2 = 3
  • Job 3: s3=4s_3 = 4, f3=5f_3 = 5

With our earliest start time strategy, we take job 1, which conflicts with both other remaining jobs. The optimal solution involves taking jobs 2 and 3 (which don't overlap). Therefore, this straetgy is not optimal.

  • Select the remaining job with the shortest interval (the one that minimizes fisif_i - s_i).
Solution

Consider the following set of 3 jobs.

  • Job 1: s1=1s_1 = 1, f1=5f_1 = 5
  • Job 2: s2=4s_2 = 4, f2=7f_2 = 7
  • Job 3: s3=6s_3 = 6, f3=10f_3 = 10

Taking the shortest job (2) locks us out of taking either job 1 or job 3. However, since job 1 and 3 don't overlap, taking both of them would be the optimal solution. Thus, selecting the remaininng job with the shortest interval is not the optimal solution.

  • Select the remaining job with the latest finish time.
Solution

Consider the following 3 jobs.

  • Job 1: s1=1s_1 = 1, f1=5f_1 = 5
  • Job 2: s2=6s_2 = 6, f2=7f_2 = 7
  • Job 3: s3=1s_3 = 1, f3=11f_3 = 11

With our greedy strategy, we would schedule job 3, and this would be the only job we would do. However, the optimal solution is to do jobs 1 and 2 (so this proposed greedy strategy is not optimal).

We can prove that our strategy of picking the earliest remaining finish time is optimal strategy. We show this using both greedy-stays-ahead and exchange argument proofs. For a problem set or exam, you'll only need to select one proof style, so be sure to pick the proof style that is the most straightforward!

Proof: Greedy Stays Ahead

Proof coming soon!

Proof: Exchange Argument

Proof coming soon!

Runtime Analysis

We can make our algorithm run in O(nlogn)O(n \log n) time. We first sort the nn jobs in order of finishing time in O(nlogn)O(n \log n) time. We select jobs by processing the intervals in this sorted order, maintaining the finish time of the most recently selected job; for each job, we check whether its start time is at least this finish time, which takes O(1)O(1) time per job, giving O(n)O(n) total. The overall runtime is dominated by the sort, so the algorithm runs in O(nlogn)O(n \log n) time.

Minimum Spanning Tree

Suppose we have an connected, undirected graph G=(V,E)G = (V, E), where edge eEe \in E has some positive edge weight cec_e. We want to find the a subset of the edges TET \subseteq E such that the graph (V,T)(V, T) is still connected and the sum of edge costs eTce\sum_{e \in T} c_e is minimized. We call TT the minimum spanning tree of our graph GG.

For example, suppose we have a graph:

Weighted graph exampleA weighted graph on vertices A, B, C, and D with edge weights 1, 2, 3, 4, and 5.13245ABCD

Can you identify the minimum spanning tree?

Solution

One spanning tree is {AB,BC,BD}\{AB, BC, BD\}, which connects all four vertices with total cost 1+2+4=71 + 2 + 4 = 7. Another spanning tree is {AC,BC,CD}\{AC, BC, CD\}, which also connects all four vertices, but has total cost 3+2+5=103 + 2 + 5 = 10.

The minimum spanning tree is

T={AB,BC,BD}T = \{AB, BC, BD\}

with total cost 77. We do not include ACAC, because AA and CC are already connected through ABCABC at lower cost, and we do not include CDCD, because DD is already connected through BDBD at lower cost.

We prove that a minimum spanning tree TT has no cycles.

Proof

Suppose for contradiction's sake that our minimum spanning tree TT has a cycle. Deleting any edge ee from the cycle will make the MST cheaper (since all weights are positive). Furthermore, the graph remains connected after deleting an edge (the two endpoints of ee are still connected by the rest of the cycle). This contradicts the minimality of our claimed MST because we have a spanning tree with a lower cost; therefore, a MST cannot contain a cycle.

In the following section, we study Kruskal's and Prim's algorithm to find a graph's minimum spanning tree (MST).

Kruskal's Algorithm

Kruskal's algorithm builds our spanning tree by greedily selecting the lowest cost edge that does not form a cycle. Suppose that our graph G=(V,E)G = (V, E) has nn vertices and mm edges.

sort all edges based on weight
S = {}, T = {}
while S != V:
consider edge e = (u, v) with lowest edge weight
if adding e to T does not create a cycle:
add u, v to S
add edge e to T
output T

To implement this into code, we can use a union find data structure; we can easily see if adding an edge will form a cycle by checking if its two endpoints belong to the same connected component. This lets us to process each edge in near O(1)O(1) time. However, our main bottleneck of our algorithm is the O(mlogm)O(m \log m) time to sort all edges. Since mn2m \le n^2, then this turns into O(mlogn)O(m \log n) overall time complexity.

Prim's Algorithm

Another strategy for building a MST is to grow it from a root node. Known as Prim's algorithm, we grow the tree outward, greedily selecting the node that can be attached using the least cost edge. Calling our root or starting node ss, here is the pseudocode for Prim's algorithm:

S = {s}, T = {}
while S != V:
find v not in S such that edge e = (u, v) has minimum weight
among all edges with one endpoint in S and other in S \ V
add v to S
add e to T
output T

We can implement Prim's algorithm using a min priority queue. We can extract each vertex exactly once from the priority queue, for a time complexity of O(nlogn)O(n \log n). Additionally, after selecting a node, we need to update the edge costs of all its neighbors (in case there is now a cheaper path to an undiscovered node). We observe that the total number of checks done is bounded by uVdeg(u)=2m\sum_{u \in V} \deg(u) = 2m. So, the total number of potential updates is O(m)O(m), each costing O(logn)O(\log n), giving O(mlogn)O(m \log n) time complexity for the update step. Since nmn \le m, the overall time complexity is O(mlogn)O(m \log n).

Visualization Demo

Minimum Spanning Tree

Start at A

The tree contains A. Prim looks only at edges crossing from the tree to the outside.

Step 1 / 6
431235162ABCDEF

Cut Property

When building a MST, we'd like a way to confirm that a particular edge must belong to it (ideally without examining every spanning tree!). This is where the cut property comes in.

Definition: Cut

A cut of a graph G=(V,E)G = (V, E) is a partition of the vertex set into two nonempty, disjoint sets SS and VSV \setminus S. An edge e=(u,v)e = (u, v) crosses the cut if one endpoint lies in SS and the other lies in VSV \setminus S.

Cut Property. Let (S,VS)(S, V \setminus S) be any cut of a connected, weighted graph GG. If ee is an edge of minimum weight among all edges crossing the cut, then there exists a minimum spanning tree of GG that contains ee. If all edge weights are distinct, this strengthens to: every MST contains ee.

Proof: Let TT be any MST GG, and suppose TT does not contain e=(u,v)e = (u, v).

  1. Since TT is a spanning tree, there is a unique path PP in TT from uu to vv.
  2. Because uu and vv lie on opposite sides of the cut, PP must cross the cut at least once. Let ee' be an edge of PP that crosses the cut.
  3. By assumption, cecec_e \le c_{e'}, since ee is a minimum-weight crossing edge.
  4. Form T=Te+eT' = T - e' + e. Removing ee' from TT splits it into two components; adding ee reconnects them (since ee also crosses the cut), so TT' is again a spanning tree.
  5. Let w(T)w(T) be the total edge weight of spanning tree TT. We have that w(T)=w(T)ce+cew(T)w(T') = w(T) - c_{e'} + c_e \le w(T)

Since TT was minimum, w(T)w(T)w(T') \ge w(T) as well, so w(T)=w(T)w(T') = w(T), meaning TT' is also an MST, and it contains ee.

To prove the stengthening of our claim, now assume that all edge weights are distinct. Suppose for contradiction's sake that some MST TT does not contain ee. Consider a similar argument with the path PP, crossing edge eee' \ne e, and the inequality cecec_{e} \le c_{e'} (since ee is the minimum cost edge crossing that cut). Since weights are distinct and eee \ne e', the previous inequality is strict:

ce<ce\begin{align*} c_{e} < c_{e'} \end{align*}

Consider the exchange of ee' for ee to produce new tree TT'.

w(T)=w(T)ce+ce<w(T)w(T') = w(T) - c_{e'} + c_{e} < w(T)

so TT' is a spanning tree with less total edge weight than TT, contradicting the minimality of TT. Hence, every MST must contain ee.

Proof of Prim's Algorithm

Now we prove the correctness of Prim's algorithm using an exchange argument. Let A={e1,e2,,en1}A = \{e_1, e_2, \dots, e_{n - 1}\} be the edges selected by Prim's algorithm, in the order they were added, and let SkS_k denote the set of vertices spanned by {e1,,ek}\{e_1, \dots, e_k\} (so S0={s}S_0 = \{s\}). Let OO be any MST. If A=OA = O, we are done. Otherwise, consider the case AOA \ne O.

Since AOA \ne O, there is some smallest index kk such that ekOe_k \notin O (so e1,,ek1Oe_1, \dots, e_{k-1} \in O, but ekOe_k \notin O). Write ek=(u,v)e_k = (u, v) with uSk1u \in S_{k-1} and vSk1v \notin S_{k-1}; by definition of Prim's algorithm, eke_k is a minimum-weight edge crossing the cut (Sk1,VSk1)(S_{k-1}, V \setminus S_{k-1}).

Since OO is a spanning tree, there is a unique path PP from uu to vv in OO. Since uSk1u \in S_{k-1} and vSk1v \notin S_{k-1}, PP must cross the cut (Sk1,VSk1)(S_{k-1}, V\setminus S_{k-1}) at some edge ee'. Because eke_k is a minimum-weight edge crossing this cut, we have cekcec_{e_k} \le c_{e'}.

Note also that eeie' \ne e_i for any i<ki < k: each eie_i (for i<ki < k) has both endpoints in Sk1S_{k-1}, so it cannot cross the cut, while ee' does.

Now form T=Oe+ekT' = O - e' + e_k. Since ee' lies on the path between uu and vv in OO, removing it separates uu from vv; adding ek=(u,v)e_k = (u,v) back reconnects them, so TT' is again a spanning tree. Its weight is

w(T)=w(O)ce+cekw(O).w(T') = w(O) - c_{e'} + c_{e_k} \le w(O).

Since OO is optimal, w(T)w(O)w(T') \ge w(O) as well, so w(T)=w(O)w(T') = w(O), meaning TT' is also an MST. Moreover, since ee1,,ek1e' \ne e_1, \dots, e_{k-1}, none of these edges were removed, so TT' contains e1,,ek1,eke_1, \dots, e_{k-1}, e_k: one more edge of AA than OO did.

We can repeat this process: at each step, we exchange one edge of our current optimal tree for the next edge of AA it disagrees on, strictly increasing the number of edges shared with AA while preserving optimality. Since there are only n1n-1 edges total, this process terminates after at most n1n-1 exchanges, at which point our tree equals AA exactly. Since every tree produced along the way is an MST, AA is an MST.

Practice

Problem 1. Suppose we have a undirected graph G=(V,E)G = (V, E) with edge weights ce>0c_e > 0 for each edge eEe \in E, and a minimum spanning tree TT in this graph. Suppose we squared the cost of each edge eEe \in E, i.e. let ce=ce2c'_e = c_e^2. Is TT still a MST with these new edge weights? If yes, provide a brief explanation; if no, provide a counterexample.

Solution

True. Recall that the MST produced by Kruskal's algorithm depends only on the sorted order of the edge weights. Squaring the weights does not change their relative ordering (since all the weights are positive).

Problem 2. [Task Scheduling] Suppose you have nn tasks to complete. Task ii takes pi>0p_i > 0 time to complete and has priority qi>0q_i > 0, representing how costly it is to wait and not do the task. If task ii is completed at time TiT_i, then the total cost is i=1nqiTi\sum_{i = 1}^n q_i T_i. Your goal is to decide what order to do the tasks in order to minimize this total.

Consider the following two greedy strategies:

  • Most important task: do tasks in decreasing order of qiq_i.
  • Best value-per-minute: do tasks in decreasing order of the ratio qi/piq_i / p_i.

Assume all task times, priority values, and ratios are distinct. For both strategies, prove that it gives the optimal schedule or provide a counterexample.

Solution

Most important task. This is not optimal. Consider a scenario with two tasks.

  • Task 1: p1=100p_1 = 100, q1=2q_1 = 2
  • Task 2: p2=1p_2 = 1, q2=1q_2 = 1

Using the greedy strategy, we first do task 1. This gives us a total cost of 1002+1011=301100 \cdot 2 + 101 \cdot 1 = 301. However, if we were to do task 2 first, we would end up with a lower cost of 11+1012=2031 \cdot 1 + 101 \cdot 2 = 203. Thus, doing the most important tasks first is not an optimal strategy.

Best value-per-minute. This is optimal. We prove this via an exchange argument. Let the solution produced by our greedy algorithm be AA, and the optimal ordering be OO. If A=OA = O, then we are done. Thus, we consider the case where AOA \ne O. If AOA \ne O, then the optimal ordering differs from the ordering specified by the greedy strategy. This means that there exists two tasks ii and i+1i + 1 in our optimal ordering that do not respect the best value-per-minute ordering, i.e.

qipi<qi+1pi+1\begin{align*} \frac{q_i}{p_i} < \frac{q_{i+1}}{p_{i+1}} \end{align*}

Consider swapping the order in which the two tasks are completed. We observe that all the other finish times TjT_j are the same (so the costs contributed by these other tasks stays the same). However, FiF_i and Fi+1F_{i + 1} change.

  • We complete task ii after task i+1i + 1, so FiF_{i} increases by pi+1p_{i + 1}. The overall cost contributed by task ii increases by qipi+1q_i \cdot p_{i + 1}.
  • We now complete task i+1i + 1 first, so Fi+1F_{i + 1} decreases by pip_{i}, reducing the cost by qi+1piq_{i + 1} \cdot p_{i}.

Since we assumed qipi<qi+1pi+1\frac{q_i}{p_i} < \frac{q_{i+1}}{p_{i+1}}, we have qipi+1<qi+1piq_i \cdot p_{i + 1} < q_{i + 1} \cdot p_{i}. Since the decrease is larger than the increase in total cost, swapping the order in which we complete task ii and i+1i + 1 improves our total cost. This contradicts the assumption that we started with an optimal schedule. We can repeat this argument for any pair of tasks that doesn't use the best value-per-minute ordering. Therefore, the optimal ordering is by decreasing ratio qi/piq_i / p_i.

Problem 3. [Tunneling Dilemma] Caleb recently opened a new aquarium with a star attraction orca whale. The orca is showcased in any one of the aquarium's nn tanks. Lifting the orca out of the water by crane and transporting it from tank to tank is stressful and risky, so Caleb wants it to be able to swim between any two tanks instead.

For any pair of tanks iji \ne j with 1i,jn1 \le i, j \le n, Caleb can build a tunnel between them at construction cost cij>0c_{ij} > 0. The orca can swim through any tunnel he builds, in either direction, and may pass through intermediate tanks on the way. Caleb wants to choose a set of tunnels FF so that the orca can be moved from any tank to any other tank using only tunnels in FF, minimizing the total construction cost {i,j}Fcij\sum_{\{i, j\} \in F} c_{ij}.

Give a polynomial time algorithm that takes as input the costs cijc_{ij} and outputs a minimum-cost set of tunnels meeting Caleb's requirement.

Hint

Can we represent the problem as a graph? Can we apply one of our MST algorithm to it?

Solution

Let GG be the complete graph on the nn tanks with edge weights cijc_{ij}. Run Kruskal's algorithm on GG and output the resulting tree TT.

Correctness

Write c(F)={i,j}Fcijc(F) = \sum_{\{i,j\} \in F} c_{ij}, and call FF feasible if the orca can reach any tank from any other using only tunnels in FF. Since tunnels are bidirectional and the orca may pass through intermediate tanks, FF is feasible exactly when (V,F)(V, F) is connected.

Claim

Some optimal feasible set is a spanning tree of GG.

Proof. Feasible sets exist since GG is complete, so let FF be optimal. It is connected. Suppose it contained a cycle CC, and let e={x,y}Ce = \{x, y\} \in C. Then (V,Fe)(V, F - e) is still connected: any path using ee can be rerouted along the xx-yy path CeC - e, giving a walk and hence a path. So FeF - e is feasible with

c(Fe)=c(F)ce<c(F)c(F - e) = c(F) - c_e < c(F)

since ce>0c_e > 0, contradicting optimality. Thus FF is connected and acyclic, i.e. a spanning tree. \blacksquare

Every spanning tree is connected and hence feasible, so by the Claim the minimum over feasible sets equals the minimum over spanning trees. Kruskal is correct, so TT attains the latter, and TT is feasible. Hence TT is optimal.

Running time

GG has m=(n2)=O(n2)m = \binom{n}{2} = O(n^2) edges, so Kruskal runs in O(mlogm)=O(n2log(n2))=O(n2logn)O(m \log m) = O(n^2 \log (n^2)) = O(n^2 \log n), which is polynomial.