📜  工作选择问题——损失最小化策略 | 2套

📅  最后修改于: 2021-10-25 06:26:01             🧑  作者: Mango

我们之前讨论过一种损失最小化策略:作业排序问题——损失最小化。在本文中,我们将研究另一种适用于略有不同问题的策略。
给定一个从 1 到 N 编号的 N 个产品序列。每个产品都有一个用 (Vi) 表示的数量。限制是,一旦商品完成,其数量开始以每天固定的百分比 (P) 衰减。所有商品都以相同的速度衰减,而且每件商品都需要一天时间才能完成。
我们需要找出货物的生产顺序,以便使货物的总体积最大化。
示例 1:

Input: 4, 2, 151, 15, 1, 52, 12 and P = 10%
Output: 222.503

解:在最佳作业序列中,所有作业结束时剩余的货物总量为 222.503
示例 2:

Input: 3, 1, 41, 52, 15, 4, 1, 63, 12 and P = 20%
Output: 145.742

解:在最佳作业序列中,所有作业结束时剩余的货物总量为 145.72

解释 –
由于这是一个优化问题,我们可以尝试使用贪心算法来解决这个问题。每天我们都会从尚未生产的商品中进行选择。因此,我们所需要的只是一个本地选择标准或启发式方法,当应用于选择工作时,它将为我们提供最佳结果。
除了尝试最大化音量之外,我们还可以尝试最小化损失。由于从所有商品中可以获得的总体积也是恒定的,如果我们最大限度地减少损失,我们就可以保证得到最佳答案。
现在考虑任何具有体积 V 的商品
第 1 天后的损失:PV
第 2 天后的损失:PV + P(1-P)V 或 V(2P-P^2)
第 3 天后的损失:V(2P-P^2) + P(1 – 2P + P^2)V 或 V(3P – 3P^2 + P^3)
随着天数增加,损失也会增加。因此,诀窍是确保货物在生产后不会闲置。此外,由于我们需要每天至少生产一项作业,因此我们应该先执行低容量作业,然后再执行高容量作业。由于两个因素,该策略有效。

  1. 大批量商品在生产后不会闲置。
  2. 随着交易量的减少,每天的损失也会减少,因此对于小批量商品,几天后损失变得可以忽略不计。

因此,为了获得最佳解决方案,我们稍后会生产更大批量的商品。第一天选择产量最少的商品并生产。从货物清单中删除生产的货物。第二天重复同样的动作。当还有待生产的商品时,继续重复。
在计算生产结束时的总产量时,请记住第 i 天生产的商品将有

(1-P)^{N-i}

其剩余体积的倍数。显然,在第 N 天(最后一天)生产的商品的体积将保持不变,因为

(1-P)^{N-N} = 1

算法 –

Step 1: Add all the goods to a min-heap       
Step 2: Repeat following steps while Queue is not empty
        Extract the good  at the head of the heap
        Print the good
        Remove the good from the heap
        [END OF LOOP]
Step 4: End

复杂性——
我们正好执行 N 个 push() 和 pop() 操作,每个操作都需要 log (N) 时间。因此,时间复杂度为 O( N * log(N) )。
下面是解决方案的实现。

C++
// C++ implementation of the
// above approach
#include 
using namespace std;
 
void optimum_sequence_jobs(vector& V, double P)
{
    int j = 1, N = V.size() - 1;
    double result = 0;
 
    // Create a min-heap (priority queue)
    priority_queue, greater > Queue;
 
    // Add all goods to the Queue
    for (int i = 1; i <= N; i++)
        Queue.push(V[i]);   
 
    // Pop Goods from Queue as long as it is not empty
    while (!Queue.empty()) {
 
        // Print the good
        cout << Queue.top() << " ";
 
        // Add the Queue to the vector
        // so that total voulme can be calculated
        V[j++] = Queue.top();
        Queue.pop();
    }
 
    // Calclulating volume of goods left when all
    // are produced. Move from right to left of
    // sequence multiplying each volume by
    // increasing powers of 1 - P starting from 0
    for (int i = N; i >= 1; i--)
        result += pow((1 - P), N - i) * V[i];   
 
    // Print result
    cout << endl << result << endl;
}
 
// Driver code
int main()
{
    // For implementation simplicity days are numbered
    // from 1 to N. Hence 1 based indexing is used
    vector V{ -1, 3, 5, 4, 1, 2, 7, 6, 8, 9, 10 };
 
    // 10% loss per day
    double P = 0.10;
 
    optimum_sequence_jobs(V, P);
 
    return 0;
}


Java
// Java implementation of the
// above approach
import java.util.*;
class GFG{
 
  static void optimum_sequence_jobs(int[] V,
                                    double P)
{
    int j = 1, N = V.length - 1;
    double result = 0;
 
    // Create a min-heap
    // (priority queue)
    PriorityQueue Queue =
                  new PriorityQueue<>();
 
    // Add all goods to the Queue
    for (int i = 1; i <= N; i++)
      Queue.add(V[i]);   
 
    // Pop Goods from Queue as
    // long as it is not empty
    while (!Queue.isEmpty())
    {
      // Print the good
      System.out.print(Queue.peek() +
                       " ");
 
      // Add the Queue to the vector
      // so that total voulme can
      // be calculated
      V[j++] = Queue.peek();
      Queue.remove();
    }
 
    // Calclulating volume of goods
    // left when all are produced.
    // Move from right to left of
    // sequence multiplying each
    // volume by increasing powers
    // of 1 - P starting from 0
    for (int i = N; i >= 1; i--)
      result += Math.pow((1 - P),
                          N - i) * V[i];   
 
    // Print result
    System.out.printf("\n%.2f\n",
                      result );
  }
 
// Driver code
public static void main(String[] args)
{
  // For implementation simplicity
  // days are numbered from 1 to N.
  // Hence 1 based indexing is used
  int[] V = {-1, 3, 5, 4, 1,
             2, 7, 6, 8, 9, 10};
 
  // 10% loss per day
  double P = 0.10;
 
  optimum_sequence_jobs(V, P);
}
}
 
// This code is contributed by Amit Katiyar


输出 –

1 2 3 4 5 6 7 8 9 10 
41.3811




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