Activity Scheduling Problem
Explore the activity scheduling problem and understand how to select the maximum number of compatible activities using greedy algorithms. Learn to optimize solutions by sorting activities by finish time, reducing complexity, and applying an iterative approach suitable for coding interviews.
We'll cover the following...
Problem Statement
Say you are given activities with their start and finish times. Select the maximum number of activities that can be performed by a single person, assuming that a person can only work on a single activity at a time.
Mathematically, Let be the set of activities that compete for a resource. Each activity has its starting time and finish time with , namely, if selected, i takes place during time [ , ). No two activities can share the resource at any time point. We say that activities and are compatible if their time periods are disjoint.
The activity-selection problem is the problem of selecting the largest set of mutually compatible activities.
Brute Force Solution
We always select the first activity, and then try all the combinations of the remaining tasks that can be performed with task as the first task.
As you can see from the code above, such an approach is very naive. Plus the time complexity is since we try all possible combinations of the activities.
However, a slight greedy tweak can really help us reduce the time complexity of our solution
By looking at the figure above, we can deduce that if we sort the activities on the final time of the activities, we can intuitively assign the resources that are free to the next task. Let’s have a look at the pseudocode for solving this algorithm:
Greedy Iterative Solution
Pseudocode
GreedyIterativeActivitySelector(A, s, f):
Sort A by finish times stored in f
S = {A[1]}
k = 1
n = A.length
for i = 2 to n:
if s[i] ≥ f[k]:
S = S U {A[i]}
k = i
return
This algorithm is called Greedy-Iterative-Activity-Selector.
In this pseudocode, is an array containing the activities, is an array containing the start times of the activities in , and is an array containing the finish times of the activities in . Note, these arrays are indexed starting from 1 up to the length of the corresponding array.
Firstly, sort the array of activities in increasing order of finish times by using the finish times stored in the array . This operation can be done in time, using the fastest available sorting algorithms. For revision of sorting algorithms see this chapter. Next, create a set to store the selected activities, and initialize it with the activity . Start iterating from the second element of that array up to its last element and, if the start time of the th activity ( ) is greater or equal to the finish time of the last selected activity (), then is compatible with the selected activities in the set , and thus it can be added to .
The algorithm is (without sorting) because each activity is examined exactly once across all calls; each recursive call starts at , where the previous call left off.
If the activities need to be sorted, the overall problem can be solved in .