Open In App

Maximize average of the ratios of N pairs by M increments

Improve
Improve
Like Article
Like
Save
Share
Report

Given an array arr[] consisting of N pairs and a positive integer M, the task is to maximize the average of the ratio of the pairs by incrementing the first and second elements of any pair by 1 exactly M times.

Examples:

Input: arr[] = {{1, 2}, {3, 5}, {2, 2}}, M = 2
Output: 0.783333
Explanation:
Below are the operations performed:
Operation 1: Increment the first and second element of pair {1, 2} by 1. Now, the array modifies to {{2, 3}, {3, 5}, {2, 2}}.
Operation 2: Increment the first and second element of pair {2, 3} by 1. Now, the array modifies to {{3, 4}, {3, 5}, {2, 2}}.
After the above operations, the average of the ratio of the pairs is ((3/4) + (3/5) + (2/2))/3 = 0.7833 which is the maximum possible.

Input: arr[] = {{2, 5}, {3, 5}}, M = 3
Output: 0.619048

Approach: The given problem can be solved by storing the increase incurred in the ratio by applying operation on the pairs using Max-heap and then keep popping the values M times from the heap and add to the overall sum. Follow the steps below to solve the problem:

  • Initialize a priority queue, say PQ of pairs to store the corresponding change in average and the index of the pair if one operation is applied on it.
  • Initialize a variable, say sum as 0 to store the maximum average of the ratio of the pairs.
  • Traverse the given array of pairs arr[] and find the increase in the ratio after adding 1 to both the values of the pair and push the value to priority queue PQ. Also, add the ratio of the ith pair to the variable sum.
  • Iterate until the value of M is positive and perform the following steps:
  • After completing the above steps, print the value of the sum divided by N as the result.

Below is the implementation of the above approach:

C++




// C++ program for the above approach
 
#include <bits/stdc++.h>
using namespace std;
 
// Function to find the change in the
// ratio in pair after applying operation
double change(int pass, int total)
{
    double currentPassRatio, newPassRatio;
    double increase;
 
    // Stores the current ratio
    currentPassRatio = ((double)pass)
                       / total;
 
    // Stores the new ratio
    newPassRatio = ((double)(pass + 1))
                   / (total + 1);
 
    // Stores the increase in ratio
    increase = newPassRatio
               - currentPassRatio;
 
    // Returns the change
    return increase;
}
 
// Function to find the maximum
// average of the ratio of the
// pairs by applying M increments
double maximumAverage(
    vector<vector<int> > v, int M,
    int N)
{
    // Stores the required result
    double sum = 0;
 
    double increase, average;
 
    // Declare a priority queue
    // for storing the increments
    priority_queue<pair<double, int> > pq;
    for (int i = 0; i < N; i++) {
 
        // Store the increase in the ratio
        // after applying one operation
        increase = change(v[i][0], v[i][1]);
 
        // Push the increased value and
        // index value in priority queue
        pq.push({ increase, i });
 
        // Store the ratio
        average = v[i][0] * 1.0 / v[i][1];
 
        // Update the value of sum
        sum += average;
    }
 
    // Iterate while M > 0
    while (M > 0) {
 
        // Add the maximum change
        // to the sum
        sum += pq.top().first;
 
        int i = pq.top().second;
 
        // Remove the element from
        // the priority queue
        pq.pop();
 
        // Increase the pairs elements
        // by 1 on which operation
        // is applied
        v[i][0] += 1;
        v[i][1] += 1;
 
        // Push the updated change of
        // the pair in priority queue
        pq.push({ change(v[i][0], v[i][1]), i });
 
        // Decrease the operation count
        M--;
    }
 
    // Update the value of the sum by
    // dividing it by N
    double ans = sum / N;
 
    // Return the result
    return ans;
}
 
// Driver Code
int main()
{
    vector<vector<int> > V
        = { { 1, 2 }, { 3, 5 }, { 2, 2 } };
    int M = 2;
    int N = V.size();
    cout << maximumAverage(V, M, N);
 
    return 0;
}


Java




import java.util.*;
 
// Comparer for the SortedList
class DescendingComparer<T extends Comparable<T> >
  implements Comparator<T> {
  public int compare(T x, T y)
  {
    if (x == null) {
      return -1;
    }
    if (y == null) {
      return 1;
    }
 
    return x.compareTo(y);
  }
}
 
class GFG {
  // Function to find the change in the
  // ratio in pair after applying operation
  static double change(int pass, int total)
  {
    double currentPassRatio, newPassRatio;
    double increase;
 
    // Stores the current ratio
    currentPassRatio = ((double)pass) / total;
 
    // Stores the new ratio
    newPassRatio = ((double)(pass + 1)) / (total + 1);
 
    // Stores the increase in ratio
    increase = newPassRatio - currentPassRatio;
 
    // Returns the change
    return increase;
  }
 
  // Function to find the maximum
  // average of the ratio of the
  // pairs by applying M increments
  static double maximumAverage(List<List<Integer> > v,
                               int M, int N)
  {
    // Stores the required result
    double sum = 0;
 
    double increase, average;
 
    // Declare a priority queue
    // for storing the increments
    PriorityQueue<Double> pq = new PriorityQueue<>(
      new DescendingComparer<Double>());
    for (int i = 0; i < N; i++) {
      // Store the increase in the ratio
      // after applying one operation
      increase
        = change(v.get(i).get(0), v.get(i).get(1));
 
      // Push the increased value and
      // index value in priority queue
      pq.add(increase);
 
      // Store the ratio
      average = v.get(i).get(0) * 1.0
        / (1.0 * v.get(i).get(1));
 
      // Update the value of sum
      sum += average;
    }
 
    // Iterate while M > 0
    while (M > 0) {
      // Add the maximum change
      // to the sum
      // Remove the element from
      // the priority queue
      sum += pq.poll();
 
      // Decrease the operation count
      M--;
    }
 
    // Update the value of the sum by
    // dividing it by N
    double ans = sum / (1.0 * N);
 
    // Return the result
    return ans;
  }
 
  // Main function
  public static void main(String[] args)
  {
    List<List<Integer> > V = new ArrayList<>();
    V.add(Arrays.asList(1, 2));
    V.add(Arrays.asList(3, 5));
    V.add(Arrays.asList(2, 2));
    int M = 2;
    int N = V.size();
    System.out.println(maximumAverage(V, M, N));
  }
}
 
// This code is contributed by phasing17.


Python3




# python program for the above approach
 
# Function to find the change in the
# ratio in pair after applying operation
def change(pas, total):
 
    # Stores the current ratio
    currentPassRatio = pas/ total
 
    # Stores the new ratio
    newPassRatio = (pas + 1) / (total + 1)
 
    # Stores the increase in ratio
    increase = newPassRatio - currentPassRatio
 
    # Returns the change
    return increase
 
# Function to find the maximum
# average of the ratio of the
# pairs by applying M increments
def maximumAverage(v, M, N):
   
    # Stores the required result
    sum = 0
 
    increase, average = 0, 0
 
    # Declare a priority queue
    # for storing the increments
    pq = []
    for i in range(N):
        # Store the increase in the ratio
        # after applying one operation
        increase = change(v[i][0], v[i][1])
 
        # Push the increased value and
        # index value in priority queue
        pq.append([increase, i ])
 
        # Store the ratio
        average = v[i][0] * 1.0 / v[i][1]
 
        # Update the value of sum
        sum += average
    pq = sorted(pq)
 
    # Iterate while M > 0
    while (M > 0):
 
        # Add the maximum change
        # to the sum
        sum += pq[-1][0]
 
        i = pq[-1][1]
 
        # Remove the element from
        # the priority queue
        del pq[-1]
 
        # Increase the pairs elements
        # by 1 on which operation
        # is applied
        v[i][0] += 1
        v[i][1] += 1
 
        # Push the updated change of
        # the pair in priority queue
        pq.append([change(v[i][0], v[i][1]), i])
 
        # Decrease the operation count
        M -= 1
        pq = sorted(pq)
 
    # Update the value of the sum by
    # dividing it by N
    ans = sum / N
 
    # Return the result
    return ans
 
# Driver Code
if __name__ == '__main__':
    V =  [[1, 2],  [3, 5],  [2, 2]]
    M = 2
    N = len(V)
    print (round(maximumAverage(V, M, N),6))
 
    # This code is contributed by mohit kumar 29.


C#




// C# Program to find maximum average of the ratio of the pairs
// by applying M increments
using System;
using System.Collections.Generic;
using System.Linq;
 
// Comparer for the SortedList
class DescendingComparer<T> : IComparer<T> {
  public int Compare(T x, T y)
  {
    if (x == null)
      return -1;
    if (y == null)
      return 1;
    return Comparer<T>.Default.Compare(y, x);
  }
}
 
class Program {
  // Function to find the change in the
  // ratio in pair after applying operation
  static double Change(int pass, int total)
  {
    double currentPassRatio, newPassRatio;
    double increase;
 
    // Stores the current ratio
    currentPassRatio = ((double)pass) / total;
 
    // Stores the new ratio
    newPassRatio = ((double)(pass + 1)) / (total + 1);
 
    // Stores the increase in ratio
    increase = newPassRatio - currentPassRatio;
 
    // Returns the change
    return increase;
  }
 
  // Function to find the maximum
  // average of the ratio of the
  // pairs by applying M increments
  static double MaximumAverage(List<List<int> > v, int M,
                               int N)
  {
    // Stores the required result
    double sum = 0;
 
    double increase, average;
 
    // Declare a priority queue
    // for storing the increments
    var pq = new SortedList<double, int>(
      new DescendingComparer<double>());
    for (int i = 0; i < N; i++) {
      // Store the increase in the ratio
      // after applying one operation
      increase = Change(v[i][0], v[i][1]);
 
      // Push the increased value and
      // index value in priority queue
      pq.Add(increase, i);
 
      // Store the ratio
      average = v[i][0] * 1.0 / v[i][1];
 
      // Update the value of sum
      sum += average;
    }
 
    // Iterate while M > 0
    while (M > 0) {
      // Add the maximum change
      // to the sum
      sum += pq.First().Key;
 
      int i = pq.First().Value;
 
      // Remove the element from
      // the priority queue
      pq.RemoveAt(0);
 
      // Increase the pairs elements
      // by 1 on which operation
      // is applied
      v[i][0] += 1;
      v[i][1] += 1;
 
      // Push the updated change of
      // the pair in priority queue
      pq.Add(Change(v[i][0], v[i][1]), i);
 
      // Decrease the operation count
      M--;
    }
 
    // Update the value of the sum by
    // dividing it by N
    double ans = sum / N;
 
    // Return the result
    return ans;
  }
 
  // Main function
  static void Main(string[] args)
  {
    var V
      = new List<List<int> >{ new List<int>{ 1, 2 },
                             new List<int>{ 3, 5 },
                             new List<int>{ 2, 2 } };
    int M = 2;
    int N = V.Count;
    Console.WriteLine(MaximumAverage(V, M, N));
  }
}
 
// This code is contributed by phasing17.


Javascript




<script>
 
// JavaScript program for the above approach
 
// Function to find the change in the
// ratio in pair after applying operation
function change(pass,total)
{
    let currentPassRatio, newPassRatio;
    let increase;
     
    // Stores the current ratio
    currentPassRatio = (pass)
                       / total;
  
    // Stores the new ratio
    newPassRatio = ((pass + 1))
                   / (total + 1);
  
    // Stores the increase in ratio
    increase = newPassRatio
               - currentPassRatio;
  
    // Returns the change
    return increase;
}
 
// Function to find the maximum
// average of the ratio of the
// pairs by applying M increments
function maximumAverage(v,M,N)
{
    // Stores the required result
    let sum = 0;
  
    let increase, average;
  
    // Declare a priority queue
    // for storing the increments
    let pq=[];
    for (let i = 0; i < N; i++) {
  
        // Store the increase in the ratio
        // after applying one operation
        increase = change(v[i][0], v[i][1]);
  
        // Push the increased value and
        // index value in priority queue
        pq.push([ increase, i ]);
  
        // Store the ratio
        average = v[i][0] * 1.0 / v[i][1];
  
        // Update the value of sum
        sum += average;
    }
      
    pq.sort(function(a,b){return a[0]-b[0]});
    // Iterate while M > 0
    while (M > 0) {
  
        // Add the maximum change
        // to the sum
        sum += pq[pq.length-1][0];
  
        let i = pq[pq.length-1][1];
  
        // Remove the element from
        // the priority queue
        pq.pop();
  
        // Increase the pairs elements
        // by 1 on which operation
        // is applied
        v[i][0] += 1;
        v[i][1] += 1;
  
        // Push the updated change of
        // the pair in priority queue
        pq.push([ change(v[i][0], v[i][1]), i ]);
  
        // Decrease the operation count
        M--;
        pq.sort(function(a,b){return a[0]-b[0]});
    }
  
    // Update the value of the sum by
    // dividing it by N
    let ans = sum / N;
  
    // Return the result
    return ans;
}
 
// Driver Code
let V=[[ 1, 2 ], [ 3, 5 ], [ 2, 2 ] ];
let M = 2;
let N=V.length;
document.write( maximumAverage(V, M, N).toFixed(6));
 
// This code is contributed by patel2127
 
</script>


Output: 

0.783333

 

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



Last Updated : 06 Feb, 2023
Like Article
Save Article
Previous
Next
Share your thoughts in the comments
Similar Reads