Skip to main content

Welcome to a Grasp lesson

Create a free account to keep studying and create your own study path.

Lesson 18

Activity Selection: A Greedy Approach

Recommended resources

Hello! Welcome to your next lesson on algorithms.

In our last session, we built the theoretical foundation for greedy algorithms, identifying the two crucial properties a problem needs: optimal substructure and the greedy choice property. We briefly used the Activity Selection Problem to see a proof of the greedy choice property using an "exchange argument."

Today, we'll put that theory into practice. Our entire focus will be on the Activity Selection Problem. We will:

  1. Define the problem and explore several intuitive but incorrect greedy strategies to understand why the optimal choice works.
  2. Formulate the correct greedy strategy.
  3. Implement the algorithm and analyze its complexity.
  4. Solidify our understanding of why this strategy is guaranteed to be optimal.

By the end of this lesson, you will be able to confidently apply a greedy strategy to solve the Activity Selection Problem.

1. What is the Activity Selection Problem?

Imagine you have a single resource, like a lecture hall or a CPU, and a list of requested activities, each with a known start and finish time. Your goal is to select the maximum number of activities that can be performed without any of them overlapping.

Activity Selection Problem: Greedy Algorithm Visualization
This image visualizes a set of activities on a timeline. The goal is to pick the maximum number of non-overlapping activities. Here, A1, A4, and A5 are selected, while A2, A3, and A6 are discarded due to conflicts.

Formally, we are given a set of activities , where each activity has a start time and a finish time . We want to find a maximum-size subset of mutually compatible (non-overlapping) activities. Two activities and are compatible if their intervals and do not overlap, meaning or .


2. Finding the Right Greedy Choice

How do we decide which activity to pick first? A greedy algorithm needs a simple, local criterion. Let's consider a few intuitive ideas. Do they work? This exploration is crucial for building a deep understanding of why the correct strategy is not always the most obvious one.

The following video discusses a few plausible, yet incorrect, greedy strategies and shows why they fail using counter-examples. It's an excellent way to see the thought process behind designing a correct greedy algorithm.

Algorithms Lecture 15: Greedy Algorithms, Activity Selection Problem

Watch this segment from 'Algorithms Lecture 15' by Ghassan Shobaki. The lecturer explores two intuitive greedy heuristics—shortest duration and earliest start time—and demonstrates with clear counter-examples why they do not guarantee an optimal solution.

Watch from 02:48 to 14:40. Pay close attention to the counter-examples provided for: The strategy of picking the activity with the minimum duration. The strategy of picking the activity with the earliest start time.

As the video demonstrated, seemingly logical choices can fail:

  • Earliest start time: Fails if the first activity is very long, blocking many other shorter activities.
  • Shortest duration: Fails if a short-duration activity happens to conflict with two other activities that could have otherwise been scheduled together.
  • Fewest conflicts: This also seems plausible but is more complex to compute and can also be proven to fail.

This leads us to the strategy that does work.


3. The Optimal Strategy: Earliest Finish Time

The correct and optimal greedy strategy is to always choose the activity that finishes first.

The intuition is that by picking the activity that finishes earliest, we free up the resource as soon as possible, thus maximizing the remaining time for other activities.

Let's see this strategy in action.

Mastering the Activity Selection Problem: A Comprehensive Guide

This guide from AlgoCademy provides a clear, step-by-step walkthrough of the greedy approach and includes a Python implementation.

Please read the sections 'Approach to Solving the Activity Selection Problem' and 'Implementing the Solution'. Focus on the three-step process described and how it translates directly into the Python code.

The algorithm is beautifully simple:

  1. Sort the activities in ascending order of their finish times.
  2. Select the first activity from the sorted list and add it to your solution set. Let's say its finish time is last_finish.
  3. Iterate through the remaining sorted activities. For each activity, if its start time is greater than or equal to last_finish, select it, add it to the solution set, and update last_finish to the finish time of this new activity.

Complexity Analysis

As you saw in the reading, the complexity of this algorithm is dominated by the initial sorting step.

  • Time Complexity: for sorting the activities. The subsequent iteration through the sorted list takes time. Therefore, the total time complexity is .
  • Space Complexity: or depending on the implementation. If you can sort the array in-place and just need to store the selected activities, it's where is the size of the output. If you create a new sorted copy, it's .

4. Proof of Correctness: A Deeper Look

You have a working algorithm. But as we discussed, the key challenge with greedy algorithms is proving they are correct. In our last lesson, you saw the "exchange argument" for the greedy choice property. Let's now formalize the complete proof for this problem, which also requires optimal substructure.

This section is for deepening your theoretical understanding, which you've expressed an interest in.

Step 1: Prove the Greedy Choice Property

We must show that the greedy choice (picking the activity with the earliest finish time) is always part of some optimal solution.

  • Let be the set of activities, sorted by finish time, so is the activity with the earliest finish time. Our greedy choice is .
  • Let be an optimal solution. Let be the first activity in (also sorted by finish time).
  • Case 1: . The greedy choice is already in this optimal solution. We're done.
  • Case 2: . We can construct a new solution by replacing with . Since has the earliest finish time of all activities, we know . Because the activities in are compatible with , and finishes no later than , they must also be compatible with . Therefore, is a valid, non-overlapping schedule. It has the same number of activities as , so it is also optimal.

This proves that there is always an optimal solution that begins with the greedy choice.

Step 2: Prove Optimal Substructure

We must show that an optimal solution to the problem contains optimal solutions to its subproblems.

  • After making the greedy choice , we are left with a subproblem: find the maximum number of activities from the set . This is the set of activities that start after finishes.
  • Let our overall solution be , where is the solution to the subproblem on set .
  • We can prove by contradiction (a "cut-and-paste" argument) that must be an optimal solution for the subproblem. If there were a better solution for , say , with , then we could form a new solution . This solution would have more activities than , contradicting our assumption that was optimal.

Because the problem has both the greedy choice property and optimal substructure, our greedy algorithm is guaranteed to produce a globally optimal solution.

For a more dynamic explanation of the proof, especially the exchange argument, the following video is excellent.

Interval Scheduling Maximization (Proof w/ Exchange Argument)

This video from Back To Back SWE provides a very clear, step-by-step walkthrough of the exchange argument, visually transforming a hypothetical optimal solution into the greedy solution.

If you'd like to solidify your understanding of the proof, watch from 05:09 to 20:19. The presenter does a great job of explaining how, at every point of difference between a greedy and an optimal solution, you can safely 'exchange' for the greedy choice.


Conclusion

We have successfully taken the Activity Selection Problem from definition to a proven, efficient solution. This process is a model for how to approach problems that might be solvable with a greedy strategy.

Key Takeaways:

  • The Activity Selection Problem aims to maximize the number of non-overlapping activities from a given set.
  • The optimal greedy strategy is to sort activities by finish time and iteratively select the first available compatible activity. Other intuitive strategies, like choosing by start time or duration, are not optimal.
  • The algorithm's time complexity is , determined by the sorting step.
  • The correctness of this greedy algorithm is formally proven by demonstrating it possesses both the greedy choice property (via an exchange argument) and optimal substructure.

Preview of the Next Lesson:

In the next lesson, we will explore another classic problem solved with a greedy algorithm: Huffman coding. This will show you a very different application of the greedy paradigm, used in nearly all modern data compression schemes. You'll see how making a locally optimal choice at each step—combining the two least frequent characters—leads to a globally optimal compression tree.