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++
#include <iostream>
#include <algorithm>
using namespace std;
struct Job
{
int start, finish, profit;
};
bool myfunction(Job s1, Job s2)
{
return (s1.finish < s2.finish);
}
int binarySearch(Job jobs[], int index)
{
int lo = 0, hi = index - 1;
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;
}
int findMaxProfit(Job arr[], int n)
{
sort(arr, arr+n, myfunction);
int *table = new int [n];
table[0] = arr[0].profit;
for ( int i=1; i<n; i++)
{
int inclProf = arr[i].profit;
int l = binarySearch(arr, i);
if (l != -1)
inclProf += table[l];
table[i] = max(inclProf, table[i-1]);
}
int result = table[n-1];
delete [] table;
return result;
}
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;
}
|
Java
import java.util.Arrays;
import java.util.Comparator;
class Job
{
int start, finish, profit;
Job( int start, int finish, int profit)
{
this .start = start;
this .finish = finish;
this .profit = profit;
}
}
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
{
static public int binarySearch(Job jobs[], int index)
{
int lo = 0 , hi = index - 1 ;
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 ;
}
static public int schedule(Job jobs[])
{
Arrays.sort(jobs, new JobComparator());
int n = jobs.length;
int table[] = new int [n];
table[ 0 ] = jobs[ 0 ].profit;
for ( int i= 1 ; i<n; i++)
{
int inclProf = jobs[i].profit;
int l = binarySearch(jobs, i);
if (l != - 1 )
inclProf += table[l];
table[i] = Math.max(inclProf, table[i- 1 ]);
}
return table[n- 1 ];
}
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));
}
}
|
Python
class Job:
def __init__( self , start, finish, profit):
self .start = start
self .finish = finish
self .profit = profit
def binarySearch(job, start_index):
lo = 0
hi = start_index - 1
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
def schedule(job):
job = sorted (job, key = lambda j: j.finish)
n = len (job)
table = [ 0 for _ in range (n)]
table[ 0 ] = job[ 0 ].profit;
for i in range ( 1 , n):
inclProf = job[i].profit
l = binarySearch(job, i)
if (l ! = - 1 ):
inclProf + = table[l];
table[i] = max (inclProf, table[i - 1 ])
return table[n - 1 ]
job = [Job( 1 , 2 , 50 ), Job( 3 , 5 , 20 ),
Job( 6 , 19 , 100 ), Job( 2 , 100 , 200 )]
print ( "Optimal profit is" ),
print schedule(job)
|
C#
using System;
using System.Collections.Generic;
class Job {
public int start, finish, profit;
public Job( int start, int finish, int profit)
{
this .start = start;
this .finish = finish;
this .profit = profit;
}
}
class JobComparer : IComparer<Job> {
public int Compare(Job a, Job b)
{
return a.finish < b.finish
? -1
: a.finish == b.finish ? 0 : 1;
}
}
class WeightedIntervalScheduling {
static public int BinarySearch(List<Job> jobs,
int index)
{
int lo = 0, hi = index - 1;
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;
}
static public int Schedule(List<Job> jobs)
{
jobs.Sort( new JobComparer());
int n = jobs.Count;
int [] table = new int [n];
table[0] = jobs[0].profit;
for ( int i = 1; i < n; i++) {
int inclProf = jobs[i].profit;
int l = BinarySearch(jobs, i);
if (l != -1)
inclProf += table[l];
table[i] = Math.Max(inclProf, table[i - 1]);
}
return table[n - 1];
}
public static void Main( string [] args)
{
List<Job> jobs = new List<Job>{
new Job(1, 2, 50), new Job(3, 5, 20),
new Job(6, 19, 100), new Job(2, 100, 200)
};
Console.WriteLine( "Optimal profit is "
+ Schedule(jobs));
}
}
|
Javascript
<script>
class Job{
constructor(start, finish, profit){
this .start = start
this .finish = finish
this .profit = profit
}
}
function binarySearch(job, start_index){
let lo = 0
let hi = start_index - 1
while (lo <= hi){
let mid = Math.floor((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
}
function schedule(job){
job.sort((a,b)=>a.finish - b.finish)
let n = job.length
let table = new Array(n).fill(0)
table[0] = job[0].profit;
for (let i=1;i<n;i++){
inclProf = job[i].profit
l = binarySearch(job, i)
if (l != -1)
inclProf += table[l];
table[i] = Math.max(inclProf, table[i - 1])
}
return table[n-1]
}
let job = [ new Job(1, 2, 50), new Job(3, 5, 20),
new Job(6, 19, 100), new Job(2, 100, 200)]
document.write( "Optimal profit is " )
document.write(schedule(job), "</br>" )
</script>
|
Output:
Optimal profit is 250
Time complexity: O(n Log n)
Auxiliary Space: O(n) because using extra space for array table
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