📜  作业排序问题——损失最小化

📅  最后修改于: 2021-10-26 05:09:10             🧑  作者: Mango

我们有 N 个工作,编号为 1 到 N。对于每个活动,让 Ti 表示完成工作所需的天数。在开始为工作 i 工作之前每延迟一天,就会造成 Li 的损失。
我们需要找到一个序列来完成工作,以便将整体损失降至最低。我们一次只能从事一项工作。

如果多个这样的解决方案是可能的,那么我们需要给出字典序最小的排列(即字典顺序中最早的)。

例子:

Input : L = {3, 1, 2, 4} and 
        T = {4, 1000, 2, 5}
Output : 3, 4, 1, 2
Explanation: We should first complete 
job 3, then jobs 4, 1, 2 respectively.

Input : L = {1, 2, 3, 5, 6} 
        T = {2, 4, 1, 3, 2}
Output : 3, 5, 4, 1, 2 
Explanation: We should complete jobs 
3, 5, 4, 1 and then 2 in this order.

让我们考虑两个极端情况,并从中推导出一般情况的解决方案。

  1. 所有作业的完成时间相同,即所有 i 的 Ti = k。由于所有作业都需要相同的时间来完成,因此我们应该首先选择损失(Li)大的作业。我们应该选择损失最大的工作,并尽早完成它们。
    因此这是一个贪心算法。仅基于 Li 按降序对作业进行排序。
  2. 所有工作都有相同的惩罚。由于所有工作都有相同的惩罚,我们将首先执行那些需要较少时间来完成的工作。这将最小化总延迟,因此也最小化发生的总损失。
    这也是一种贪心算法。根据 Ti 按升序对作业进行排序。或者我们也可以按 1/Ti 的降序排序。

      从上述案例中,我们不难看出,我们不应仅根据 Li 或 Ti 对作业进行排序。相反,我们应该根据 Li/Ti 的比率降序对作业进行排序。

      如果我们对工作进行稳定排序,我们可以获得字典上最小的工作排列。一个稳定排序的例子是归并排序。

      为了获得最准确的结果,请避免将 Li 除以 Ti。相反,比较两个比率,如分数。要比较 a/b 和 c/d,请比较 ad 和 bc。

      // CPP program to minimize loss using stable sort.
      #include 
      #include 
      #include 
      using namespace std;
        
      #define all(c) c.begin(), c.end()
        
      // Each job is represented as a pair of int and pair.
      // This is done to provide implementation simplicity
      // so that we can use functions provided by algorithm
      // header
      typedef pair > job;
        
      // compare function is given so that we can specify
      // how to compare a pair of jobs
      bool cmp_pair(job a, job b)
      {
          int a_Li, a_Ti, b_Li, b_Ti;
          a_Li = a.second.first;
          a_Ti = a.second.second;
          b_Li = b.second.first;
          b_Ti = b.second.second;
        
          // To compare a/b and c/d, compare ad and bc
          return (a_Li * b_Ti) > (b_Li * a_Ti);
      }
        
      void printOptimal(int L[], int T[], int N)
      {
          vector list; // (Job Index, Si, Ti)
        
          for (int i = 0; i < N; i++) {
              int t = T[i];
              int l = L[i];
        
              // Each element is: (Job Index, (Li, Ti) )
              list.push_back(make_pair(i + 1, make_pair(l, t)));
          }
        
          stable_sort(all(list), cmp_pair);
        
          // traverse the list and print job numbers
          cout << "Job numbers in optimal sequence are\n";
          for (int i = 0; i < N; i++) 
              cout << list[i].first << " ";   
        
      }
        
      // Driver code
      int main()
      {
          int L[] = { 1, 2, 3, 5, 6 };
          int T[] = { 2, 4, 1, 3, 2 };
          int N = sizeof(L) / sizeof(L[0]);
          printOptimal(L, T, N);
          return 0;
      }
      

      输出:

      Job numbers in optimal sequence are
      3 5 4 1 2 
      

      时间复杂度:O(N log N)
      空间复杂度:O(N)

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