Open In App

Job Selection Problem – Loss Minimization Strategy | Set 2

Last Updated : 20 Dec, 2022
Improve
Improve
Like Article
Like
Save
Share
Report

We have discussed one loss minimization strategy before: Job Sequencing Problem – Loss Minimization. In this article, we will look at another strategy that applies to a slightly different problem.
We are given a sequence of N goods of production numbered from 1 to N. Each good has a volume denoted by (Vi). The constraint is that once a good has been completed its volume starts decaying at a fixed percentage (P) per day. All goods decay at the same rate and further each good takes one day to complete. 

We are required to find the order in which the goods should be produced so that the overall volume of goods is maximized.

Example 1: 

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

Solution: In the optimum sequence of jobs, the total volume of goods left at the end of all jobs is 222.503

Example 2:  

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

Solution: In the optimum sequence of jobs the total volume of goods left at the end of all jobs is 145.72

Explanation:

Since this is an optimization problem, we can try to solve this problem by using a greedy algorithm. On each day we make a selection from among the goods that are yet to be produced. Thus, all we need is a local selection criterion or heuristic, which when applied to select the jobs will give us the optimum result.

Instead of trying to maximize the volume, we can also try to minimize the losses. Since the total volume that can be obtained from all goods is also constant, if we minimize the losses we are guaranteed to get the optimum answer.

Now consider any good having volume V 

Loss after Day 1: PV 
Loss after Day 2: PV + P(1-P)V or V(2P-P^2) 
Loss after Day 3: V(2P-P^2) + P(1 – 2P + P^2)V or V(3P – 3P^2 + P^3)

As the day increases the losses to increase. So the trick would be to ensure that the goods are not kept idle after production. Further, since we are required to produce at least one job per day, we should perform low-volume jobs, and then perform high-volume jobs. 

This strategy works due to two factors.  

  1. High Volume goods are not kept idle after production.
  2. As the volume decreases the loss per day too decreases, so for low-volume goods, the losses become negligible after a few days.

So in order to obtain the optimum solution we produce the larger volume goods later on. For the first day select the good with the least volume and produce it. Remove the produced good from the list of goods. For the next day repeat the same. Keep repeating while there are goods left to be produced.
When calculating the total volume at the end of production, keep in mind the good produced on day i, will have 

(1-P)^{N-i}

times its volume left. Evidently, the good produced on day N (last day) will have its volume intact since 
(1-P)^{N-N} = 1

Algorithm:

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

Below is the implementation of the solution.

C++

// C++ implementation of the
// above approach
#include <bits/stdc++.h>
using namespace std;
 
void optimum_sequence_jobs(vector<int>& V, double P)
{
    int j = 1, N = V.size() - 1;
    double result = 0;
 
    // Create a min-heap (priority queue)
    priority_queue<int, vector<int>, greater<int> > 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 volume can be calculated
        V[j++] = Queue.top();
        Queue.pop();
    }
 
    // Calculating 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<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);
 
    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<Integer> 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 volume can
      // be calculated
      V[j++] = Queue.peek();
      Queue.remove();
    }
 
    // Calculating 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

                    

Python3

# Python implementation of the
# above approach
from heapq import heappop, heappush, heapify
 
# Function to find the optimum sequence
def optimum_sequence_jobs(V: list, P: float):
    N = len(V) - 1
    j = 1
    result = 0
 
    Queue = []
 
    for i in V[1:]:
        heappush(Queue, i)
 
    while Queue:
        top = heappop(Queue)
        V[j] = top
        print(top, end=" ")
        j += 1
 
    print()
    # Calculating with decay
    for i in range(N, 0, -1):
        result += V[i] * pow((1 - P), (N - i))
 
    print(f"{result:.4f}")
 
 
if __name__ == "__main__":
    V = [-1, 3, 5, 4, 1, 2, 7, 6, 8, 9, 10]
 
    # 10% loss per day
    P = 0.10
 
    optimum_sequence_jobs(V, P)
 
    # This code is contributed by kraanzu.

                    

C#

// C# implementation of the
// above approach
using System;
using System.Collections.Generic;
 
public 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)
    List<int> Queue =
      new List<int>();
 
    // Add all goods to the Queue
    for (int i = 1; i <= N; i++)
      Queue.Add(V[i]);   
    Queue.Sort();
 
    // Pop Goods from Queue as
    // long as it is not empty
    while (Queue.Count!=0)
    {
      // Print the good
      Console.Write(Queue[0] +
                    " ");
 
      // Add the Queue to the vector
      // so that total volume can
      // be calculated
      V[j++] = Queue[0];
      Queue.RemoveAt(0);
    }
 
    // Calculating 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
    Console.Write("\n{0:F2}\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 shikhasingrajput

                    

Javascript

<script>
    // Javascript implementation of the
    // above approach
     
    // function to rectify sorting of 
    // numerical values in Javascript
    function sorter(a, b){
      return a - b;
    }
     
    function optimum_sequence_jobs(V,P){
        var j = 1, N = V.length - 1;
        var result = 0;
         
        // Since Javascript doesn't support priority queues
        // create a copy of V and sort it in ascending order
        // to simulate a priority queue
        var Queue = [];
         
        // Add all goods to the Queue
        for(var i=1;i<=N;i++){
            Queue[i]=V[i];
        }
         
        // Javascript treats elements as strings due to which
        // the standard .sort() function will treat "10" to
        // be smaller than "5" because "1" is smaller than "2".
        // In order to rectify the situation, sorter is used
        Queue.sort(sorter);
         
        // Pop Goods from Queue as
        // long as it is not empty
        for(var i = 0; i < Queue.length - 1; i++){
             
            // Print the good
            document.write(Queue[i]+" ");
             
            // Add the Queue to the vector
            // so that total volume can
            // be calculated
            V[j]=Queue[i];
            j++;
        }
         
        // Calculating 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 (var i = N; i >= 1; i--){
            result += ((Math.pow((1 - P),(N - i))) * V[i]);
        }
         
        // Print result
        document.write("\n");
        document.write(result.toFixed(4)); 
         
    }
         
    // For implementation simplicity
    // days are numbered from 1 to N.
    // Hence 1 based indexing is used
    let V = [-1, 3, 5, 4, 1, 2, 7, 6, 8, 9, 10];
     
    // 10% loss per day
    var P = 0.10;
     
    optimum_sequence_jobs(V, P);
     
    // This code is contributed by shruti456rawal
</script>

                    

Output
1 2 3 4 5 6 7 8 9 10 
41.3811

Time Complexity: O(N log N)
Auxiliary Space: O(N)



Like Article
Suggest improvement
Share your thoughts in the comments

Similar Reads