📜  加权作业调度 |设置 2(使用 LIS)

📅  最后修改于: 2021-09-17 16:14:59             🧑  作者: Mango

给定 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] 的加权作业调度。因此,对于索引 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 )。

如果您希望与专家一起参加现场课程,请参阅DSA 现场工作专业课程学生竞争性编程现场课程