# Weighted Job Scheduling in O(n Log n) time

Given N jobs where every job is represented by following three elements of it.

- Start Time
- Finish Time
- Profit or Value Associated

Find the maximum profit subset of jobs such that no two jobs in the subset overlap.

Example:

Input: Number of Jobs n = 4 Job Details {Start Time, Finish Time, Profit} Job 1: {1, 2, 50} Job 2: {3, 5, 20} Job 3: {6, 19, 100} Job 4: {2, 100, 200} Output: The maximum profit is 250. We can get the maximum profit by scheduling jobs 1 and 4. Note that there is longer schedules possible Jobs 1, 2 and 3 but the profit with this schedule is 20+50+100 which is less than 250.

We strongly recommend to refer below article as a prerequisite for this.

Weighted Job Scheduling

The above problem can be solved using following recursive solution.

1) First sort jobs according to finish time. 2) Now apply following recursive process. // Here arr[] is array of n jobs findMaximumProfit(arr[], n) { a) if (n == 1) return arr[0]; b) Return the maximum of following two profits. (i) Maximum profit by excluding current job, i.e., findMaximumProfit(arr, n-1) (ii) Maximum profit by including the current job }How to find the profit including current job?The idea is to find the latest job before the current job (in sorted array) that doesn't conflict with current job 'arr[n-1]'. Once we find such a job, we recur for all jobs till that job and add profit of current job to result. In the above example, "job 1" is the latest non-conflicting for "job 4" and "job 2" is the latest non-conflicting for "job 3".

We have discussed recursive and Dynamic Programming based approaches in the previous article. The implementations discussed in above post uses linear search to find the previous non-conflicting job. In this post, Binary Search based solution is discussed. The time complexity of Binary Search based solution is O(n Log n).

The algorithm is:

- Sort the jobs by non-decreasing finish times.
- For each i from 1 to n, determine the maximum value of the schedule from the subsequence of jobs[0..i]. Do this by comparing the inclusion of job[i] to the schedule to the exclusion of job[i] to the schedule, and then taking the max.

To find the profit with inclusion of job[i]. we need to find the latest job that doesn’t conflict with job[i]. The idea is to use Binary Search to find the latest non-conflicting job.

## C/C++

`// C++ program for weighted job scheduling using Dynamic ` `// Programming and Binary Search ` `#include <iostream> ` `#include <algorithm> ` `using` `namespace` `std; ` ` ` `// A job has start time, finish time and profit. ` `struct` `Job ` `{ ` ` ` `int` `start, finish, profit; ` `}; ` ` ` `// A utility function that is used for sorting events ` `// according to finish time ` `bool` `myfunction(Job s1, Job s2) ` `{ ` ` ` `return` `(s1.finish < s2.finish); ` `} ` ` ` `// A Binary Search based function to find the latest job ` `// (before current job) that doesn't conflict with current ` `// job. "index" is index of the current job. This function ` `// returns -1 if all jobs before index conflict with it. ` `// The array jobs[] is sorted in increasing order of finish ` `// time. ` `int` `binarySearch(Job jobs[], ` `int` `index) ` `{ ` ` ` `// Initialize 'lo' and 'hi' for Binary Search ` ` ` `int` `lo = 0, hi = index - 1; ` ` ` ` ` `// Perform binary Search iteratively ` ` ` `while` `(lo <= hi) ` ` ` `{ ` ` ` `int` `mid = (lo + hi) / 2; ` ` ` `if` `(jobs[mid].finish <= jobs[index].start) ` ` ` `{ ` ` ` `if` `(jobs[mid + 1].finish <= jobs[index].start) ` ` ` `lo = mid + 1; ` ` ` `else` ` ` `return` `mid; ` ` ` `} ` ` ` `else` ` ` `hi = mid - 1; ` ` ` `} ` ` ` ` ` `return` `-1; ` `} ` ` ` `// The main function that returns the maximum possible ` `// profit from given array of jobs ` `int` `findMaxProfit(Job arr[], ` `int` `n) ` `{ ` ` ` `// Sort jobs according to finish time ` ` ` `sort(arr, arr+n, myfunction); ` ` ` ` ` `// Create an array to store solutions of subproblems. table[i] ` ` ` `// stores the profit for jobs till arr[i] (including arr[i]) ` ` ` `int` `*table = ` `new` `int` `[n]; ` ` ` `table[0] = arr[0].profit; ` ` ` ` ` `// Fill entries in table[] using recursive property ` ` ` `for` `(` `int` `i=1; i<n; i++) ` ` ` `{ ` ` ` `// Find profit including the current job ` ` ` `int` `inclProf = arr[i].profit; ` ` ` `int` `l = binarySearch(arr, i); ` ` ` `if` `(l != -1) ` ` ` `inclProf += table[l]; ` ` ` ` ` `// Store maximum of including and excluding ` ` ` `table[i] = max(inclProf, table[i-1]); ` ` ` `} ` ` ` ` ` `// Store result and free dynamic memory allocated for table[] ` ` ` `int` `result = table[n-1]; ` ` ` `delete` `[] table; ` ` ` ` ` `return` `result; ` `} ` ` ` `// Driver program ` `int` `main() ` `{ ` ` ` `Job arr[] = {{3, 10, 20}, {1, 2, 50}, {6, 19, 100}, {2, 100, 200}}; ` ` ` `int` `n = ` `sizeof` `(arr)/` `sizeof` `(arr[0]); ` ` ` `cout << ` `"Optimal profit is "` `<< findMaxProfit(arr, n); ` ` ` `return` `0; ` `} ` |

*chevron_right*

*filter_none*

## Python

`# Python program for weighted job scheduling using Dynamic ` `# Programming and Binary Search ` ` ` `# Class to represent a job ` `class` `Job: ` ` ` `def` `__init__(` `self` `, start, finish, profit): ` ` ` `self` `.start ` `=` `start ` ` ` `self` `.finish ` `=` `finish ` ` ` `self` `.profit ` `=` `profit ` ` ` ` ` `# A Binary Search based function to find the latest job ` `# (before current job) that doesn't conflict with current ` `# job. "index" is index of the current job. This function ` `# returns -1 if all jobs before index conflict with it. ` `# The array jobs[] is sorted in increasing order of finish ` `# time. ` `def` `binarySearch(job, start_index): ` ` ` ` ` `# Initialize 'lo' and 'hi' for Binary Search ` ` ` `lo ` `=` `0` ` ` `hi ` `=` `start_index ` `-` `1` ` ` ` ` `# Perform binary Search iteratively ` ` ` `while` `lo <` `=` `hi: ` ` ` `mid ` `=` `(lo ` `+` `hi) ` `/` `/` `2` ` ` `if` `job[mid].finish <` `=` `job[start_index].start: ` ` ` `if` `job[mid ` `+` `1` `].finish <` `=` `job[start_index].start: ` ` ` `lo ` `=` `mid ` `+` `1` ` ` `else` `: ` ` ` `return` `mid ` ` ` `else` `: ` ` ` `hi ` `=` `mid ` `-` `1` ` ` `return` `-` `1` ` ` `# The main function that returns the maximum possible ` `# profit from given array of jobs ` `def` `schedule(job): ` ` ` ` ` `# Sort jobs according to finish time ` ` ` `job ` `=` `sorted` `(job, key ` `=` `lambda` `j: j.finish) ` ` ` ` ` `# Create an array to store solutions of subproblems. table[i] ` ` ` `# stores the profit for jobs till arr[i] (including arr[i]) ` ` ` `n ` `=` `len` `(job) ` ` ` `table ` `=` `[` `0` `for` `_ ` `in` `range` `(n)] ` ` ` ` ` `table[` `0` `] ` `=` `job[` `0` `].profit; ` ` ` ` ` `# Fill entries in table[] using recursive property ` ` ` `for` `i ` `in` `range` `(` `1` `, n): ` ` ` ` ` `# Find profit including the current job ` ` ` `inclProf ` `=` `job[i].profit ` ` ` `l ` `=` `binarySearch(job, i) ` ` ` `if` `(l !` `=` `-` `1` `): ` ` ` `inclProf ` `+` `=` `table[l]; ` ` ` ` ` `# Store maximum of including and excluding ` ` ` `table[i] ` `=` `max` `(inclProf, table[i ` `-` `1` `]) ` ` ` ` ` `return` `table[n` `-` `1` `] ` ` ` `# Driver code to test above function ` `job ` `=` `[Job(` `1` `, ` `2` `, ` `50` `), Job(` `3` `, ` `5` `, ` `20` `), ` ` ` `Job(` `6` `, ` `19` `, ` `100` `), Job(` `2` `, ` `100` `, ` `200` `)] ` `print` `(` `"Optimal profit is"` `), ` `print` `schedule(job) ` |

*chevron_right*

*filter_none*

## Java

`// Java program for Weighted Job Scheduling in O(nLogn) ` `// time ` `import` `java.util.Arrays; ` `import` `java.util.Comparator; ` ` ` `// Class to represent a job ` `class` `Job ` `{ ` ` ` `int` `start, finish, profit; ` ` ` ` ` `// Constructor ` ` ` `Job(` `int` `start, ` `int` `finish, ` `int` `profit) ` ` ` `{ ` ` ` `this` `.start = start; ` ` ` `this` `.finish = finish; ` ` ` `this` `.profit = profit; ` ` ` `} ` `} ` ` ` `// Used to sort job according to finish times ` `class` `JobComparator ` `implements` `Comparator<Job> ` `{ ` ` ` `public` `int` `compare(Job a, Job b) ` ` ` `{ ` ` ` `return` `a.finish < b.finish ? -` `1` `: a.finish == b.finish ? ` `0` `: ` `1` `; ` ` ` `} ` `} ` ` ` `public` `class` `WeightedIntervalScheduling ` `{ ` ` ` `/* A Binary Search based function to find the latest job ` ` ` `(before current job) that doesn't conflict with current ` ` ` `job. "index" is index of the current job. This function ` ` ` `returns -1 if all jobs before index conflict with it. ` ` ` `The array jobs[] is sorted in increasing order of finish ` ` ` `time. */` ` ` `static` `public` `int` `binarySearch(Job jobs[], ` `int` `index) ` ` ` `{ ` ` ` `// Initialize 'lo' and 'hi' for Binary Search ` ` ` `int` `lo = ` `0` `, hi = index - ` `1` `; ` ` ` ` ` `// Perform binary Search iteratively ` ` ` `while` `(lo <= hi) ` ` ` `{ ` ` ` `int` `mid = (lo + hi) / ` `2` `; ` ` ` `if` `(jobs[mid].finish <= jobs[index].start) ` ` ` `{ ` ` ` `if` `(jobs[mid + ` `1` `].finish <= jobs[index].start) ` ` ` `lo = mid + ` `1` `; ` ` ` `else` ` ` `return` `mid; ` ` ` `} ` ` ` `else` ` ` `hi = mid - ` `1` `; ` ` ` `} ` ` ` ` ` `return` `-` `1` `; ` ` ` `} ` ` ` ` ` `// The main function that returns the maximum possible ` ` ` `// profit from given array of jobs ` ` ` `static` `public` `int` `schedule(Job jobs[]) ` ` ` `{ ` ` ` `// Sort jobs according to finish time ` ` ` `Arrays.sort(jobs, ` `new` `JobComparator()); ` ` ` ` ` `// Create an array to store solutions of subproblems. ` ` ` `// table[i] stores the profit for jobs till jobs[i] ` ` ` `// (including jobs[i]) ` ` ` `int` `n = jobs.length; ` ` ` `int` `table[] = ` `new` `int` `[n]; ` ` ` `table[` `0` `] = jobs[` `0` `].profit; ` ` ` ` ` `// Fill entries in M[] using recursive property ` ` ` `for` `(` `int` `i=` `1` `; i<n; i++) ` ` ` `{ ` ` ` `// Find profit including the current job ` ` ` `int` `inclProf = jobs[i].profit; ` ` ` `int` `l = binarySearch(jobs, i); ` ` ` `if` `(l != -` `1` `) ` ` ` `inclProf += table[l]; ` ` ` ` ` `// Store maximum of including and excluding ` ` ` `table[i] = Math.max(inclProf, table[i-` `1` `]); ` ` ` `} ` ` ` ` ` `return` `table[n-` `1` `]; ` ` ` `} ` ` ` ` ` `// Driver method to test above ` ` ` `public` `static` `void` `main(String[] args) ` ` ` `{ ` ` ` `Job jobs[] = {` `new` `Job(` `1` `, ` `2` `, ` `50` `), ` `new` `Job(` `3` `, ` `5` `, ` `20` `), ` ` ` `new` `Job(` `6` `, ` `19` `, ` `100` `), ` `new` `Job(` `2` `, ` `100` `, ` `200` `)}; ` ` ` ` ` `System.out.println(` `"Optimal profit is "` `+ schedule(jobs)); ` ` ` `} ` `} ` |

*chevron_right*

*filter_none*

Output:

Optimal profit is 250

This article is contributed by **Daniel Ray**. Please write comments if you find anything incorrect, or you want to share more information about the topic discussed above

## Recommended Posts:

- Space and time efficient Binomial Coefficient
- Assembly Line Scheduling | DP-34
- Shortest path with exactly k edges in a directed and weighted graph
- Weighted Job Scheduling
- Minimum time to finish tasks without skipping two consecutive
- Find Jobs involved in Weighted Job Scheduling
- Weighted Job Scheduling | Set 2 (Using LIS)
- Minimum time to write characters using insert, delete and copy operation
- Amazon Interview Experience | Set 389 (On -Campus for Full Time)
- Probability of reaching a point with 2 or 3 steps at a time
- Maximum difference of zeros and ones in binary string | Set 2 (O(n) time)
- Sum of products of all combination taken (1 to n) at a time
- Dynamic Programming | Wildcard Pattern Matching | Linear Time and Constant Space
- Find the probability of a state at a given time in a Markov chain | Set 1
- Minimum time required to rot all oranges | Dynamic Programming