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

📅  最后修改于: 2021-04-24 19:56:11             🧑  作者: 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)