Weighted Job Scheduling | Set 2 (Using LIS)
Last Updated :
24 Feb, 2023
Given N jobs where every job is represented by following three elements of it.
1. Start Time
2. Finish Time
3. Profit or Value Associated
Find the maximum profit subset of jobs such that no two jobs in the subset overlap.
Examples:
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:
Job 1: {1, 2, 50}
Job 4: {2, 100, 200}
Explanation: We can get the maximum profit by
scheduling jobs 1 and 4 and maximum profit is 250.
In previous post, we have discussed about Weighted Job Scheduling problem. We discussed a DP solution where we basically includes or excludes current job. In this post, another interesting DP solution is discussed where we also print the Jobs. This problem is a variation of standard Longest Increasing Subsequence (LIS) problem. We need a slight change in the Dynamic Programming solution of LIS problem.
We first need to sort jobs according to start time. Let job[0..n-1] be the array of jobs after sorting. We define vector L such that L[i] is itself is a vector that stores Weighted Job Scheduling of job[0..i] that ends with job[i]. Therefore for an index i, L[i] can be recursively written as –
L[0] = {job[0]}
L[i] = {MaxSum(L[j])} + job[i] where j < i and job[j].finish <= job[i].start
= job[i], if there is no such j
For example, consider pairs {3, 10, 20}, {1, 2, 50}, {6, 19, 100}, {2, 100, 200}
After sorting we get,
{1, 2, 50}, {2, 100, 200}, {3, 10, 20}, {6, 19, 100}
Therefore,
L[0]: {1, 2, 50}
L[1]: {1, 2, 50} {2, 100, 200}
L[2]: {1, 2, 50} {3, 10, 20}
L[3]: {1, 2, 50} {6, 19, 100}
We choose the vector with highest profit. In this case, L[1].
Below is the implementation of the above idea –
C++
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
struct Job
{
int start, finish, profit;
};
int findSum(vector<Job> arr)
{
int sum = 0;
for ( int i = 0; i < arr.size(); i++)
sum += arr[i].profit;
return sum;
}
int compare(Job x, Job y)
{
return x.start < y.start;
}
void findMaxProfit(vector<Job> &arr)
{
sort(arr.begin(), arr.end(), compare);
vector<vector<Job>> L(arr.size());
L[0].push_back(arr[0]);
for ( int i = 1; i < arr.size(); i++)
{
for ( int j = 0; j < i; j++)
{
if ((arr[j].finish <= arr[i].start) &&
(findSum(L[j]) > findSum(L[i])))
L[i] = L[j];
}
L[i].push_back(arr[i]);
}
vector<Job> maxChain;
for ( int i = 0; i < L.size(); i++)
if (findSum(L[i]) > findSum(maxChain))
maxChain = L[i];
for ( int i = 0; i < maxChain.size(); i++)
cout << "(" << maxChain[i].start << ", " <<
maxChain[i].finish << ", "
<< maxChain[i].profit << ") " ;
}
int main()
{
Job a[] = { {3, 10, 20}, {1, 2, 50}, {6, 19, 100},
{2, 100, 200} };
int n = sizeof (a) / sizeof (a[0]);
vector<Job> arr(a, a + n);
findMaxProfit(arr);
return 0;
}
|
Java
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.Comparator;
class Graph{
static class Job
{
int start, finish, profit;
public Job( int start, int finish,
int profit)
{
this .start = start;
this .finish = finish;
this .profit = profit;
}
};
static int findSum(ArrayList<Job> arr)
{
int sum = 0 ;
for ( int i = 0 ; i < arr.size(); i++)
sum += arr.get(i).profit;
return sum;
}
static void findMaxProfit(ArrayList<Job> arr)
{
Collections.sort(arr, new Comparator<Job>()
{
@Override
public int compare(Job x, Job y)
{
return x.start - y.start;
}
});
ArrayList<ArrayList<Job>> L = new ArrayList<>();
for ( int i = 0 ; i < arr.size(); i++)
{
L.add( new ArrayList<>());
}
L.get( 0 ).add(arr.get( 0 ));
for ( int i = 1 ; i < arr.size(); i++)
{
for ( int j = 0 ; j < i; j++)
{
if ((arr.get(j).finish <= arr.get(i).start) &&
(findSum(L.get(j)) > findSum(L.get(i))))
{
ArrayList<Job> copied = new ArrayList<>(
L.get(j));
L.set(i, copied);
}
}
L.get(i).add(arr.get(i));
}
ArrayList<Job> maxChain = new ArrayList<>();
for ( int i = 0 ; i < L.size(); i++)
if (findSum(L.get(i)) > findSum(maxChain))
maxChain = L.get(i);
for ( int i = 0 ; i < maxChain.size(); i++)
{
System.out.printf( "(%d, %d, %d)\n" ,
maxChain.get(i).start,
maxChain.get(i).finish,
maxChain.get(i).profit);
}
}
public static void main(String[] args)
{
Job[] a = { new Job( 3 , 10 , 20 ),
new Job( 1 , 2 , 50 ),
new Job( 6 , 19 , 100 ),
new Job( 2 , 100 , 200 ) };
ArrayList<Job> arr = new ArrayList<>(
Arrays.asList(a));
findMaxProfit(arr);
}
}
|
Javascript
function Job(start, finish, profit) {
this .start = start;
this .finish = finish;
this .profit = profit;
}
function findSum(arr) {
let sum = 0;
for (let i = 0; i < arr.length; i++) {
sum += arr[i].profit;
}
return sum;
}
function compare(x, y) {
return x.start < y.start;
}
function findMaxProfit(arr) {
arr.sort(compare);
let L = new Array(arr.length).fill([]);
L[0] = [arr[0]];
for (let i = 1; i < arr.length; i++) {
for (let j = 0; j < i; j++) {
if (arr[j].finish <= arr[i].start && findSum(L[j]) > findSum(L[i])) {
L[i] = L[j];
}
}
L[i].push(arr[i]);
}
let maxChain = [];
for (let i = 0; i < L.length; i++) {
if (findSum(L[i]) > findSum(maxChain)) {
maxChain = L[i];
}
}
for (let i = 0; i < maxChain.length; i++) {
console.log(
"(" +
maxChain[i].start +
", " +
maxChain[i].finish +
", " +
maxChain[i].profit +
") "
);
}
}
let a = [
new Job(3, 10, 20),
new Job(1, 2, 50),
new Job(2, 100, 200),
];
findMaxProfit(a);
|
C#
using System;
using System.Collections.Generic;
using System.Linq;
public class Graph
{
public class Job
{
public int start, finish, profit;
public Job( int start, int finish,
int profit)
{
this .start = start;
this .finish = finish;
this .profit = profit;
}
};
public static int FindSum(List<Job> arr)
{
int sum = 0;
for ( int i = 0; i < arr.Count; i++)
sum += arr.ElementAt(i).profit;
return sum;
}
public static void FindMaxProfit(List<Job> arr)
{
arr.Sort((x, y) => x.start.CompareTo(y.start));
List<List<Job>> L = new List<List<Job>>();
for ( int i = 0; i < arr.Count; i++)
{
L.Add( new List<Job>());
}
L[0].Add(arr[0]);
for ( int i = 1; i < arr.Count; i++)
{
for ( int j = 0; j < i; j++)
{
if ((arr[j].finish <= arr[i].start) &&
(FindSum(L[j]) > FindSum(L[i])))
{
List<Job> copied = new List<Job>(
L[j]);
L[i] = copied;
}
}
L[i].Add(arr[i]);
}
List<Job> maxChain = new List<Job>();
for ( int i = 0; i < L.Count; i++)
if (FindSum(L[i]) > FindSum(maxChain))
maxChain = L[i];
for ( int i = 0; i < maxChain.Count; i++)
{
Console.WriteLine( "({0}, {1}, {2})" ,
maxChain[i].start,
maxChain[i].finish,
maxChain[i].profit);
}
}
public static void Main(String[] args)
{
Job[] a = { new Job(3, 10, 20),
new Job(1, 2, 50),
new Job(6, 19, 100),
new Job(2, 100, 200) };
List<Job> arr = new List<Job>(a);
FindMaxProfit(arr);
}
}
|
Python3
import sys
class Job:
def __init__( self , start, finish, profit):
self .start = start
self .finish = finish
self .profit = profit
def findSum(arr):
sum = 0
for i in range ( len (arr)):
sum + = arr[i].profit
return sum
def compare(x, y):
if x.start < y.start:
return - 1
elif x.start = = y.start:
return 0
else :
return 1
def findMaxProfit(arr):
arr.sort(key = lambda x: x.start)
L = [[] for _ in range ( len (arr))]
L[ 0 ].append(arr[ 0 ])
for i in range ( 1 , len (arr)):
for j in range (i):
if arr[j].finish < = arr[i].start and findSum(L[j]) > findSum(L[i]):
L[i] = L[j][:]
L[i].append(arr[i])
maxChain = []
for i in range ( len (L)):
if findSum(L[i]) > findSum(maxChain):
maxChain = L[i]
for i in range ( len (maxChain)):
print ( "({}, {}, {})" . format (
maxChain[i].start, maxChain[i].finish, maxChain[i].profit), end = ' ' )
if __name__ = = "__main__" :
a = [Job( 3 , 10 , 20 ), Job( 1 , 2 , 50 ), Job( 6 , 19 , 100 ), Job( 2 , 100 , 200 )]
findMaxProfit(a)
|
Output
(1, 2, 50) (2, 100, 200)
We can further optimize the above DP solution by removing findSum() function. Instead, we can maintain another vector/array to store sum of maximum profit possible till job i. The implementation can be seen here.
Time complexity of above Dynamic Programming solution is O(n2) where n is the number of Jobs.
Auxiliary space used by the program is O(n2).
Like Article
Suggest improvement
Share your thoughts in the comments
Please Login to comment...