给定N个工作,其中每个工作都由以下三个元素表示。
1.开始时间
2.完成时间
3.关联的利润或价值
找到作业的最大利润子集,以使子集中的两个作业没有重叠。
例子:
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.
在上一篇文章中,我们讨论了加权作业调度问题。我们讨论了DP解决方案,其中基本上包括或排除了当前工作。在这篇文章中,讨论了另一个有趣的DP解决方案,我们还在其中打印作业。此问题是标准最长增加子序列(LIS)问题的变体。我们需要对LIS问题的动态编程解决方案稍作更改。
我们首先需要根据开始时间对作业进行排序。令job [0..n-1]为排序后的工作数组。我们定义向量L,使得L [i]本身就是一个向量,该向量存储以job [i]结尾的job [0..i]的加权Job Scheduling。因此,对于索引i,L [i]可以递归写为–
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
例如,考虑对{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}
我们选择利润最高的向量。在这种情况下,L [1]。
以下是上述想法的实现–
C++
// C++ program for weighted job scheduling using LIS
#include
#include
#include
using namespace std;
// A job has start time, finish time and profit.
struct Job
{
int start, finish, profit;
};
// Utility function to calculate sum of all vector
// elements
int findSum(vector arr)
{
int sum = 0;
for (int i = 0; i < arr.size(); i++)
sum += arr[i].profit;
return sum;
}
// comparator function for sort function
int compare(Job x, Job y)
{
return x.start < y.start;
}
// The main function that finds the maximum possible
// profit from given array of jobs
void findMaxProfit(vector &arr)
{
// Sort arr[] by start time.
sort(arr.begin(), arr.end(), compare);
// L[i] stores stores Weighted Job Scheduling of
// job[0..i] that ends with job[i]
vector> L(arr.size());
// L[0] is equal to arr[0]
L[0].push_back(arr[0]);
// start from index 1
for (int i = 1; i < arr.size(); i++)
{
// for every j less than i
for (int j = 0; j < i; j++)
{
// L[i] = {MaxSum(L[j])} + arr[i] where j < i
// and arr[j].finish <= arr[i].start
if ((arr[j].finish <= arr[i].start) &&
(findSum(L[j]) > findSum(L[i])))
L[i] = L[j];
}
L[i].push_back(arr[i]);
}
vector maxChain;
// find one with max profit
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 << ") ";
}
// Driver Function
int main()
{
Job a[] = { {3, 10, 20}, {1, 2, 50}, {6, 19, 100},
{2, 100, 200} };
int n = sizeof(a) / sizeof(a[0]);
vector arr(a, a + n);
findMaxProfit(arr);
return 0;
}
Java
// Java program for weighted job
// scheduling using LIS
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.Comparator;
class Graph{
// A job has start time, finish time
// and profit.
static class Job
{
int start, finish, profit;
public Job(int start, int finish,
int profit)
{
this.start = start;
this.finish = finish;
this.profit = profit;
}
};
// Utility function to calculate sum of all
// ArrayList elements
static int findSum(ArrayList arr)
{
int sum = 0;
for(int i = 0; i < arr.size(); i++)
sum += arr.get(i).profit;
return sum;
}
// The main function that finds the maximum
// possible profit from given array of jobs
static void findMaxProfit(ArrayList arr)
{
// Sort arr[] by start time.
Collections.sort(arr, new Comparator()
{
@Override
public int compare(Job x, Job y)
{
return x.start - y.start;
}
});
// sort(arr.begin(), arr.end(), compare);
// L[i] stores stores Weighted Job Scheduling of
// job[0..i] that ends with job[i]
ArrayList> L = new ArrayList<>();
for(int i = 0; i < arr.size(); i++)
{
L.add(new ArrayList<>());
}
// L[0] is equal to arr[0]
L.get(0).add(arr.get(0));
// Start from index 1
for(int i = 1; i < arr.size(); i++)
{
// For every j less than i
for(int j = 0; j < i; j++)
{
// L[i] = {MaxSum(L[j])} + arr[i] where j < i
// and arr[j].finish <= arr[i].start
if ((arr.get(j).finish <= arr.get(i).start) &&
(findSum(L.get(j)) > findSum(L.get(i))))
{
ArrayList copied = new ArrayList<>(
L.get(j));
L.set(i, copied);
}
}
L.get(i).add(arr.get(i));
}
ArrayList maxChain = new ArrayList<>();
// Find one with max profit
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);
}
}
// Driver code
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 arr = new ArrayList<>(
Arrays.asList(a));
findMaxProfit(arr);
}
}
// This code is contributed by sanjeev2552
输出:
(1, 2, 50) (2, 100, 200)
我们可以通过删除findSum()函数来进一步优化上述DP解决方案。取而代之的是,我们可以维护另一个向量/数组来存储直到任务i为止的最大利润的总和。可以在这里看到实现。
上述动态编程解决方案的时间复杂度为O(n 2 ),其中n是作业数。
该程序使用的辅助空间为O(n 2 )。