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:
- 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).
- Make sure that extremity of this characteristic implies optimality.
- Prove via induction that the greedy solution actually maintains this property at every step.
- Conclude that your solution is as good as optimal.
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 . Our goal with using an exchange argument is to prove that anything in an optimal solution can be swapped with anything in our solution without losing optimality.
- Assume that your greedy solution and the optimal solution you choose differ in some way. (If this is not the case, then and we are done!).
- Show that it is possible to make progress, that is “exchange” elements in to make it more similar to your solution while preserving the optimality of .
- Show that this exchange progress terminates, and when it does where is optimal. Then, is at least as good as , so is optimal.
Make sure you exchange elements from , not ! If you exchange elements from , then you change the solution that you trying to prove is optimal!
Sample Problem: Interval Scheduling
Suppose we have a machine that can process at most job at a time. We have job requests, each with a start time and end time for with . 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 that we want to schedule on . We say two jobs and are non-conflicting if:
- job happens before job :
- job happens before job :
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: ,
- Job 2: ,
- Job 3: ,
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 ).
Solution
Consider the following set of 3 jobs.
- Job 1: ,
- Job 2: ,
- Job 3: ,
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: ,
- Job 2: ,
- Job 3: ,
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 time. We first sort the jobs in order of finishing time in 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 time per job, giving total. The overall runtime is dominated by the sort, so the algorithm runs in time.
Minimum Spanning Tree
Suppose we have an connected, undirected graph , where edge has some positive edge weight . We want to find the a subset of the edges such that the graph is still connected and the sum of edge costs is minimized. We call the minimum spanning tree of our graph .
For example, suppose we have a graph:
Can you identify the minimum spanning tree?
Solution
One spanning tree is , which connects all four vertices with total cost . Another spanning tree is , which also connects all four vertices, but has total cost .
The minimum spanning tree is
with total cost . We do not include , because and are already connected through at lower cost, and we do not include , because is already connected through at lower cost.
We prove that a minimum spanning tree has no cycles.
Proof
Suppose for contradiction's sake that our minimum spanning tree has a cycle. Deleting any edge 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 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 has vertices and 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 time. However, our main bottleneck of our algorithm is the time to sort all edges. Since , then this turns into 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 , 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 . 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 . So, the total number of potential updates is , each costing , giving time complexity for the update step. Since , the overall time complexity is .
Visualization Demo
Minimum Spanning Tree
Start at A
The tree contains A. Prim looks only at edges crossing from the tree to the outside.
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.
A cut of a graph is a partition of the vertex set into two nonempty, disjoint sets and . An edge crosses the cut if one endpoint lies in and the other lies in .
Cut Property. Let be any cut of a connected, weighted graph . If is an edge of minimum weight among all edges crossing the cut, then there exists a minimum spanning tree of that contains . If all edge weights are distinct, this strengthens to: every MST contains .
Proof: Let be any MST , and suppose does not contain .
- Since is a spanning tree, there is a unique path in from to .
- Because and lie on opposite sides of the cut, must cross the cut at least once. Let be an edge of that crosses the cut.
- By assumption, , since is a minimum-weight crossing edge.
- Form . Removing from splits it into two components; adding reconnects them (since also crosses the cut), so is again a spanning tree.
- Let be the total edge weight of spanning tree . We have that
Since was minimum, as well, so , meaning is also an MST, and it contains .
To prove the stengthening of our claim, now assume that all edge weights are distinct. Suppose for contradiction's sake that some MST does not contain . Consider a similar argument with the path , crossing edge , and the inequality (since is the minimum cost edge crossing that cut). Since weights are distinct and , the previous inequality is strict:
Consider the exchange of for to produce new tree .
so is a spanning tree with less total edge weight than , contradicting the minimality of . Hence, every MST must contain .
Proof of Prim's Algorithm
Now we prove the correctness of Prim's algorithm using an exchange argument. Let be the edges selected by Prim's algorithm, in the order they were added, and let denote the set of vertices spanned by (so ). Let be any MST. If , we are done. Otherwise, consider the case .
Since , there is some smallest index such that (so , but ). Write with and ; by definition of Prim's algorithm, is a minimum-weight edge crossing the cut .
Since is a spanning tree, there is a unique path from to in . Since and , must cross the cut at some edge . Because is a minimum-weight edge crossing this cut, we have .
Note also that for any : each (for ) has both endpoints in , so it cannot cross the cut, while does.
Now form . Since lies on the path between and in , removing it separates from ; adding back reconnects them, so is again a spanning tree. Its weight is
Since is optimal, as well, so , meaning is also an MST. Moreover, since , none of these edges were removed, so contains : one more edge of than did.
We can repeat this process: at each step, we exchange one edge of our current optimal tree for the next edge of it disagrees on, strictly increasing the number of edges shared with while preserving optimality. Since there are only edges total, this process terminates after at most exchanges, at which point our tree equals exactly. Since every tree produced along the way is an MST, is an MST.
Practice
Problem 1. Suppose we have a undirected graph with edge weights for each edge , and a minimum spanning tree in this graph. Suppose we squared the cost of each edge , i.e. let . Is 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 tasks to complete. Task takes time to complete and has priority , representing how costly it is to wait and not do the task. If task is completed at time , then the total cost is . 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 .
- Best value-per-minute: do tasks in decreasing order of the ratio .
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: ,
- Task 2: ,
Using the greedy strategy, we first do task 1. This gives us a total cost of . However, if we were to do task 2 first, we would end up with a lower cost of . 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 , and the optimal ordering be . If , then we are done. Thus, we consider the case where . If , then the optimal ordering differs from the ordering specified by the greedy strategy. This means that there exists two tasks and in our optimal ordering that do not respect the best value-per-minute ordering, i.e.
Consider swapping the order in which the two tasks are completed. We observe that all the other finish times are the same (so the costs contributed by these other tasks stays the same). However, and change.
- We complete task after task , so increases by . The overall cost contributed by task increases by .
- We now complete task first, so decreases by , reducing the cost by .
Since we assumed , we have . Since the decrease is larger than the increase in total cost, swapping the order in which we complete task and 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 .
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 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 with , Caleb can build a tunnel between them at construction cost . 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 so that the orca can be moved from any tank to any other tank using only tunnels in , minimizing the total construction cost .
Give a polynomial time algorithm that takes as input the costs 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 be the complete graph on the tanks with edge weights . Run Kruskal's algorithm on and output the resulting tree .
Correctness
Write , and call feasible if the orca can reach any tank from any other using only tunnels in . Since tunnels are bidirectional and the orca may pass through intermediate tanks, is feasible exactly when is connected.
Some optimal feasible set is a spanning tree of .
Proof. Feasible sets exist since is complete, so let be optimal. It is connected. Suppose it contained a cycle , and let . Then is still connected: any path using can be rerouted along the - path , giving a walk and hence a path. So is feasible with
since , contradicting optimality. Thus is connected and acyclic, i.e. a spanning tree.
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 attains the latter, and is feasible. Hence is optimal.
Running time
has edges, so Kruskal runs in , which is polynomial.