给定一组n个工作,其中每个工作i的截止日期di> = 1,利润pi> = 0。一次只能安排一项工作。每个作业需要1个时间单位才能完成。当且仅当工作在截止日期之前完成时,我们才能赚取利润。任务是找到能使利润最大化的工作子集。
例子:
Input: Four Jobs with following deadlines and profits
JobID Deadline Profit
a 4 20
b 1 10
c 1 40
d 1 30
Output: Following is maximum profit sequence of jobs:
c, a
Input: Five Jobs with following deadlines and profits
JobID Deadline Profit
a 2 100
b 1 19
c 2 27
d 1 25
e 3 15
Output: Following is maximum profit sequence of jobs:
c, a, e
在此已经讨论了时间复杂度O(n 2 )的贪婪解决方案。以下是简单的贪婪算法。
- 按利润降序对所有工作进行排序。
- 将结果序列初始化为已排序作业中的第一个作业。
- 对剩余的n-1个工作进行关注
- 如果当前作业可以适合当前结果序列而又不错过最后期限,则将当前作业添加到结果中。否则忽略当前工作。
贪婪解决方案中昂贵的操作是为作业分配空闲空间。我们遍历一个工作的每个时隙,并分配可能的最大时隙(
假设作业J1的截止时间为t =5。我们为该作业分配最大的空闲时间,该空闲时间小于截止时间,即4-5。现在,另一个作业J2的截止日期为5,因此分配的时间段将是3-4,因为已经将4-5分配给作业J1。
为什么要为工作分配最大的空闲时间?
现在我们分配最大可能的时隙,因为如果分配的时隙比可用时隙小,那么可能还有其他工作会错过其截止日期。
例子:
截止日期d1 = 5的J1,获利40
截止日期d2 = 1的J2,获利20
假设我们为作业J1分配了0-1的时隙。现在无法执行作业J2,因为我们将在该时间段内执行作业J1。
使用不交集进行作业排序
所有时隙最初都是单独的集合。我们首先找到所有工作的最大期限。设最大期限为m。我们创建m + 1个单独的集合。如果为作业分配了一个时间段t,其中t> = 0,则在[t-1,t]期间安排该作业。因此,具有值X的集合表示时隙[X-1,X]。
我们需要跟踪可以分配给具有截止日期的给定工作的最大可用时间段。为此,我们使用不交集数据结构的父数组。树的根始终是最新的可用插槽。如果对于截止日期d,没有可用的插槽,则root将为0。以下是详细步骤。
初始化不相交集:创建初始不相交集。
// m is maximum deadline of a job
parent = new int[m + 1];
// Every node is a parent of itself
for (int i = 0; i ≤ m; i++)
parent[i] = i;
查找:查找可用的最新时隙。
// Returns the maximum available time slot
find(s)
{
// Base case
if (s == parent[s])
return s;
// Recursive call with path compression
return parent[s] = find(parent[s]);
}
联盟:
Merges two sets.
// Makes u as parent of v.
union(u, v)
{
// update the greatest available
// free slot to u
parent[v] = u;
}
find如何返回最新的可用时隙?
最初,所有时隙都是单独的时隙。因此,返回的时隙始终是最大的。当我们为工作分配时隙“ t”时,我们以“ t-1”成为“ t”的父代的方式将“ t”与“ t-1”进行并集。为此,我们称union(t-1,t)。这意味着将来对时隙t的所有查询现在都将返回可用于t-1表示的集合的最新时隙。
执行 :
以下是上述算法的实现。
C++
// C++ Program to find the maximum profit job sequence
// from a given array of jobs with deadlines and profits
#include
using namespace std;
// A structure to represent various attributes of a Job
struct Job
{
// Each job has id, deadline and profit
char id;
int deadLine, profit;
};
// A Simple Disjoint Set Data Structure
struct DisjointSet
{
int *parent;
// Constructor
DisjointSet(int n)
{
parent = new int[n+1];
// Every node is a parent of itself
for (int i = 0; i <= n; i++)
parent[i] = i;
}
// Path Compression
int find(int s)
{
/* Make the parent of the nodes in the path
from u--> parent[u] point to parent[u] */
if (s == parent[s])
return s;
return parent[s] = find(parent[s]);
}
// Makes u as parent of v.
void merge(int u, int v)
{
//update the greatest available
//free slot to u
parent[v] = u;
}
};
// Used to sort in descending order on the basis
// of profit for each job
bool cmp(Job a, Job b)
{
return (a.profit > b.profit);
}
// Functions returns the maximum deadline from the set
// of jobs
int findMaxDeadline(struct Job arr[], int n)
{
int ans = INT_MIN;
for (int i = 0; i < n; i++)
ans = max(ans, arr[i].deadLine);
return ans;
}
int printJobScheduling(Job arr[], int n)
{
// Sort Jobs in descending order on the basis
// of their profit
sort(arr, arr + n, cmp);
// Find the maximum deadline among all jobs and
// create a disjoint set data structure with
// maxDeadline disjoint sets initially.
int maxDeadline = findMaxDeadline(arr, n);
DisjointSet ds(maxDeadline);
// Traverse through all the jobs
for (int i = 0; i < n; i++)
{
// Find the maximum available free slot for
// this job (corresponding to its deadline)
int availableSlot = ds.find(arr[i].deadLine);
// If maximum available free slot is greater
// than 0, then free slot available
if (availableSlot > 0)
{
// This slot is taken by this job 'i'
// so we need to update the greatest
// free slot. Note that, in merge, we
// make first parameter as parent of
// second parameter. So future queries
// for availableSlot will return maximum
// available slot in set of
// "availableSlot - 1"
ds.merge(ds.find(availableSlot - 1),
availableSlot);
cout << arr[i].id << " ";
}
}
}
// Driver code
int main()
{
Job arr[] = { { 'a', 2, 100 }, { 'b', 1, 19 },
{ 'c', 2, 27 }, { 'd', 1, 25 },
{ 'e', 3, 15 } };
int n = sizeof(arr) / sizeof(arr[0]);
cout << "Following jobs need to be "
<< "executed for maximum profit\n";
printJobScheduling(arr, n);
return 0;
}
Java
// Java program to find the maximum profit job sequence
// from a given array of jobs with deadlines and profits
import java.util.*;
// A Simple Disjoint Set Data Structure
class DisjointSet
{
int parent[];
// Constructor
DisjointSet(int n)
{
parent = new int[n + 1];
// Every node is a parent of itself
for (int i = 0; i <= n; i++)
parent[i] = i;
}
// Path Compression
int find(int s)
{
/* Make the parent of the nodes in the path
from u--> parent[u] point to parent[u] */
if (s == parent[s])
return s;
return parent[s] = find(parent[s]);
}
// Makes u as parent of v.
void merge(int u, int v)
{
//update the greatest available
//free slot to u
parent[v] = u;
}
}
class Job implements Comparator
{
// Each job has a unique-id, profit and deadline
char id;
int deadline, profit;
// Constructors
public Job() { }
public Job(char id,int deadline,int profit)
{
this.id = id;
this.deadline = deadline;
this.profit = profit;
}
// Returns the maximum deadline from the set of jobs
public static int findMaxDeadline(ArrayList arr)
{
int ans = Integer.MIN_VALUE;
for (Job temp : arr)
ans = Math.max(temp.deadline, ans);
return ans;
}
// Prints optimal job sequence
public static void printJobScheduling(ArrayList arr)
{
// Sort Jobs in descending order on the basis
// of their profit
Collections.sort(arr, new Job());
// Find the maximum deadline among all jobs and
// create a disjoint set data structure with
// maxDeadline disjoint sets initially.
int maxDeadline = findMaxDeadline(arr);
DisjointSet dsu = new DisjointSet(maxDeadline);
// Traverse through all the jobs
for (Job temp : arr)
{
// Find the maximum available free slot for
// this job (corresponding to its deadline)
int availableSlot = dsu.find(temp.deadline);
// If maximum available free slot is greater
// than 0, then free slot available
if (availableSlot > 0)
{
// This slot is taken by this job 'i'
// so we need to update the greatest free
// slot. Note that, in merge, we make
// first parameter as parent of second
// parameter. So future queries for
// availableSlot will return maximum slot
// from set of "availableSlot - 1"
dsu.merge(dsu.find(availableSlot - 1),
availableSlot);
System.out.print(temp.id + " ");
}
}
System.out.println();
}
// Used to sort in descending order on the basis
// of profit for each job
public int compare(Job j1, Job j2)
{
return j1.profit > j2.profit? -1: 1;
}
}
// Driver code
class Main
{
public static void main(String args[])
{
ArrayList arr=new ArrayList();
arr.add(new Job('a',2,100));
arr.add(new Job('b',1,19));
arr.add(new Job('c',2,27));
arr.add(new Job('d',1,25));
arr.add(new Job('e',3,15));
System.out.println("Following jobs need to be "+
"executed for maximum profit");
Job.printJobScheduling(arr);
}
}
Python3
# Python3 program to find the maximum profit
# job sequence from a given array of jobs
# with deadlines and profits
import sys
class DisjointSet:
def __init__(self, n):
self.parent = [i for i in range(n + 1)]
def find(self, s):
# Make the parent of nodes in the path from
# u --> parent[u] point to parent[u]
if s == self.parent[s]:
return s
self.parent[s] = self.find(self.parent[s])
return self.parent[s]
# Make us as parent of v
def merge(self, u, v):
# Update the greatest available
# free slot to u
self.parent[v] = u
def cmp(a):
return a['profit']
def findmaxdeadline(arr, n):
"""
:param arr: Job array
:param n: length of array
:return: maximum deadline from the set of jobs
"""
ans = - sys.maxsize - 1
for i in range(n):
ans = max(ans, arr[i]['deadline'])
return ans
def printjobscheduling(arr, n):
# Sort jobs in descending order on
# basis of their profit
arr = sorted(arr, key = cmp, reverse = True)
"""
Find the maximum deadline among all jobs and
create a disjoint set data structure with
max_deadline disjoint sets initially
"""
max_deadline = findmaxdeadline(arr, n)
ds = DisjointSet(max_deadline)
for i in range(n):
# find maximum available free slot for
# this job (corresponding to its deadline)
available_slot = ds.find(arr[i]['deadline'])
if available_slot > 0:
# This slot is taken by this job 'i'
# so we need to update the greatest free slot.
# Note: In merge, we make first parameter
# as parent of second parameter.
# So future queries for available_slot will
# return maximum available slot in set of
# "available_slot - 1"
ds.merge(ds.find(available_slot - 1),
available_slot)
print(arr[i]['id'], end = " ")
# Driver Code
if __name__ == "__main__":
arr = [{'id': 'a', 'deadline': 2, 'profit': 100},
{'id': 'b', 'deadline': 1, 'profit': 19},
{'id': 'c', 'deadline': 2, 'profit': 27},
{'id': 'd', 'deadline': 1, 'profit': 25},
{'id': 'e', 'deadline': 3, 'profit': 15}]
n = len(arr)
print("Following jobs need to be",
"executed for maximum profit")
printjobscheduling(arr, n)
# This code is contributed by Rajat Srivastava
Following jobs need to be executed for maximum profit
a c e