Open In App

Maximum average good ratio

Last Updated : 29 Oct, 2023
Improve
Improve
Like Article
Like
Save
Share
Report

Given an array of chocolates, each represented by a pair[good_i, total_i], where good_i is the count of eatable (good) chocolates and total_i is the total count of chocolates of that type. Additionally, you have a set of extra chocolates that can be added to any type of chocolate. The goal is to strategically distribute these extra chocolates to various types of chocolates to maximize the average good ratio across all types.

Note: The good ratio of a chocolate type is defined as the ratio of good chocolates to the total number of chocolates of that type. The average good ratio is then calculated as the sum of the individual good ratios divided by the total number of different chocolate types.

Examples:

Input: chocolates = [[1, 2], [3, 5], [4, 4]], extra_Chocolates = 2
Output: 0.7833
Explanation: You can assign the two extra chocolates to the first type. The average pass ratio will be equal to (3/4 + 3/5 + 4/4) / 3 = 0.78333

Input: chocolates = [[1, 1], [2, 2]], extra_Chocolates = 1
OutPut: 1.0000

Approach: To solve the problem follow the below idea:

  • The idea is to iteratively assign extra chocolates to the chocolate type that provides the maximum increase in average good ratio.
  • This can be achieved by calculating the difference in good ratios before and after adding an extra chocolate to each type.
  • The type with the highest difference will yield the greatest improvement in the average good ratio.

Below is the C++ implementation of the above idea:

C++




// C++ code for finding Max average good ratio
#include <bits/stdc++.h>
using namespace std;
 
double
maximizeAverageGoodRatio(vector<vector<int> >& chocolates,
                        int extraChocolates)
{
    int n = chocolates.size();
    double avg = 0, ans = 0;
    priority_queue<pair<double, int> > p;
 
    // Calculate the initial difference
    // and push to priority queue
    for (int i = 0; i < n; i++) {
        double diff = (double)(chocolates[i][0] + 1)
                        / (double)(chocolates[i][1] + 1)
                    - (double)chocolates[i][0]
                            / (double)chocolates[i][1];
        p.push({ diff, i });
    }
 
    // Distribute extra chocolates
    while (extraChocolates--) {
        int i = p.top().second;
        p.pop();
        chocolates[i][0] += 1;
        chocolates[i][1] += 1;
        double diff = (double)(chocolates[i][0] + 1)
                        / (double)(chocolates[i][1] + 1)
                    - (double)chocolates[i][0]
                            / (double)chocolates[i][1];
        p.push({ diff, i });
    }
 
    // Calculate the maximum
    // average good ratio
    for (int i = 0; i < n; i++) {
        avg = (double)chocolates[i][0]
            / (double)chocolates[i][1];
        ans += avg;
    }
 
    return ans / (double)n;
}
 
// Drivers code
int main()
{
    vector<vector<int> > chocolates
        = { { 1, 2 }, { 3, 5 }, { 4, 4 } };
    int extraChocolates = 2;
 
    // Function Call
    cout << "Max Average Good Ratio: " << fixed
        << setprecision(4)
        << maximizeAverageGoodRatio(chocolates,
                                    extraChocolates)
        << endl;
 
    return 0;
}


Java




// Java code for finding Max average good ratio
import java.util.*;
 
public class MaximizeAverageGoodRatio {
 
    static double maximizeAverageGoodRatio(ArrayList<int[]> chocolates,
                                           int extraChocolates)
    {
        int n = chocolates.size();
        double avg = 0, ans = 0;
        PriorityQueue<Pair> p = new PriorityQueue<>(Collections.reverseOrder());
 
        // Calculate the initial difference and push to priority queue
        for (int i = 0; i < n; i++) {
            double diff = (double) (chocolates.get(i)[0] + 1)
                          / (double) (chocolates.get(i)[1] + 1)
                          - (double) chocolates.get(i)[0]
                          / (double) chocolates.get(i)[1];
            p.add(new Pair(diff, i));
        }
 
        // Distribute extra chocolates
        while (extraChocolates > 0) {
            Pair pair = p.poll();
            int i = pair.index;
            chocolates.get(i)[0] += 1;
            chocolates.get(i)[1] += 1;
            double diff = (double) (chocolates.get(i)[0] + 1)
                          / (double) (chocolates.get(i)[1] + 1)
                          - (double) chocolates.get(i)[0]
                          / (double) chocolates.get(i)[1];
            p.add(new Pair(diff, i));
            extraChocolates--;
        }
 
        // Calculate the maximum average good ratio
        for (int i = 0; i < n; i++) {
            avg = (double) chocolates.get(i)[0]
                  / (double) chocolates.get(i)[1];
            ans += avg;
        }
 
        return ans / (double) n;
    }
 
    // Pair class to store difference and index
    static class Pair implements Comparable<Pair> {
        double diff;
        int index;
 
        Pair(double diff, int index) {
            this.diff = diff;
            this.index = index;
        }
 
        @Override
        public int compareTo(Pair other) {
            return Double.compare(this.diff, other.diff);
        }
    }
 
    // Driver code
    public static void main(String[] args) {
        ArrayList<int[]> chocolates = new ArrayList<>();
        chocolates.add(new int[]{1, 2});
        chocolates.add(new int[]{3, 5});
        chocolates.add(new int[]{4, 4});
 
        int extraChocolates = 2;
 
        // Function Call
        System.out.println("Max Average Good Ratio: " +
                            String.format("%.4f",
                                          maximizeAverageGoodRatio(chocolates,
                                                                   extraChocolates)));
    }
}
//This code is contributed by chinmaya121221


Python3




# Python Code
import heapq
 
def maximizeAverageGoodRatio(chocolates, extraChocolates):
    n = len(chocolates)
    avg = 0
    ans = 0
    pq = []
 
    # Calculate the initial difference
    # and push to priority queue
    for i in range(n):
        diff = (chocolates[i][0] + 1) / (chocolates[i][1] + 1) - chocolates[i][0] / chocolates[i][1]
        heapq.heappush(pq, (-diff, i))  # Using a max heap with negative values for minimum priority
 
    # Distribute extra chocolates
    while extraChocolates > 0:
        diff, i = heapq.heappop(pq)
        chocolates[i][0] += 1
        chocolates[i][1] += 1
        diff = (chocolates[i][0] + 1) / (chocolates[i][1] + 1) - chocolates[i][0] / chocolates[i][1]
        heapq.heappush(pq, (-diff, i))
 
        extraChocolates -= 1
 
    # Calculate the maximum average good ratio
    for i in range(n):
        avg = chocolates[i][0] / chocolates[i][1]
        ans += avg
 
    return ans / n
 
# Driver code
if __name__ == "__main__":
    chocolates = [[1, 2], [3, 5], [4, 4]]
    extraChocolates = 2
 
    # Function call
    result = maximizeAverageGoodRatio(chocolates, extraChocolates)
 
    print(f"Max Average Good Ratio: {result:.4f}")
 
# This code is contributed by guptapratik


C#




using System;
using System.Collections.Generic;
 
class Program
{
    static double MaximizeAverageGoodRatio(List<int[]> chocolates, int extraChocolates)
    {
        int n = chocolates.Count;
        double avg = 0, ans = 0;
        PriorityQueue<Tuple<double, int>> p = new PriorityQueue<Tuple<double, int>>(new Comparison<Tuple<double, int>>((a, b) => b.Item1.CompareTo(a.Item1)));
 
        // Calculate the initial difference and push to priority queue
        for (int i = 0; i < n; i++)
        {
            double diff = ((double)(chocolates[i][0] + 1) / (double)(chocolates[i][1] + 1)) - ((double)chocolates[i][0] / (double)chocolates[i][1]);
            p.Enqueue(new Tuple<double, int>(diff, i));
        }
 
        // Distribute extra chocolates
        while (extraChocolates > 0)
        {
            Tuple<double, int> top = p.Dequeue();
            int i = top.Item2;
            chocolates[i][0] += 1;
            chocolates[i][1] += 1;
            double diff = ((double)(chocolates[i][0] + 1) / (double)(chocolates[i][1] + 1)) - ((double)chocolates[i][0] / (double)chocolates[i][1]);
            p.Enqueue(new Tuple<double, int>(diff, i));
            extraChocolates--;
        }
 
        // Calculate the maximum average good ratio
        for (int i = 0; i < n; i++)
        {
            avg = (double)chocolates[i][0] / (double)chocolates[i][1];
            ans += avg;
        }
 
        return ans / (double)n;
    }
 
    static void Main(string[] args)
    {
        List<int[]> chocolates = new List<int[]>
        {
            new int[] { 1, 2 },
            new int[] { 3, 5 },
            new int[] { 4, 4 }
        };
        int extraChocolates = 2;
 
        // Function Call
        Console.WriteLine("Max Average Good Ratio: " + MaximizeAverageGoodRatio(chocolates, extraChocolates).ToString("F4"));
    }
}
 
public class PriorityQueue<T>
{
    private List<T> data;
    private Comparison<T> comparison;
 
    public PriorityQueue(Comparison<T> comparison)
    {
        this.data = new List<T>();
        this.comparison = comparison;
    }
 
    public void Enqueue(T item)
    {
        data.Add(item);
        int ci = data.Count - 1;
        while (ci > 0)
        {
            int pi = (ci - 1) / 2;
            if (comparison(data[ci], data[pi]) >= 0)
                break;
            T tmp = data[ci]; data[ci] = data[pi]; data[pi] = tmp;
            ci = pi;
        }
    }
 
    public T Dequeue()
    {
        if (data.Count == 0)
            throw new InvalidOperationException("Queue is empty");
        int li = data.Count - 1;
        T frontItem = data[0];
        data[0] = data[li];
        data.RemoveAt(li);
 
        --li;
        int ci = 0;
        while (true)
        {
            int pi = ci * 2 + 1;
            if (pi > li) break;
            int rc = pi + 1;
            if (rc <= li && comparison(data[rc], data[pi]) < 0)
                pi = rc;
            if (comparison(data[ci], data[pi]) <= 0) break;
            T tmp = data[ci]; data[ci] = data[pi]; data[pi] = tmp;
            ci = pi;
        }
        return frontItem;
    }
 
    public T Peek()
    {
        if (data.Count == 0)
            throw new InvalidOperationException("Queue is empty");
        return data[0];
    }
 
    public int Count
    {
        get { return data.Count; }
    }
}
//Contributed by Aditi Tyagi


Javascript




// Javascript code for the above approach
 
class MaximizeAverageGoodRatio {
    static maximizeAverageGoodRatio(chocolates, extraChocolates) {
        const n = chocolates.length;
        let avg = 0,
            ans = 0;
        const p = new PriorityQueue((a, b) => b.diff - a.diff);
 
        // Calculate the initial difference and push to priority queue
        for (let i = 0; i < n; i++) {
            const diff = (chocolates[i][0] + 1) /
                          (chocolates[i][1] + 1) - chocolates[i][0] / chocolates[i][1];
            p.enqueue(new Pair(diff, i));
        }
 
        // Distribute extra chocolates
        while (extraChocolates > 0) {
            const pair = p.dequeue();
            const i = pair.index;
            chocolates[i][0] += 1;
            chocolates[i][1] += 1;
            const diff = (chocolates[i][0] + 1) /
            (chocolates[i][1] + 1) - chocolates[i][0] / chocolates[i][1];
            p.enqueue(new Pair(diff, i));
            extraChocolates--;
        }
 
        // Calculate the maximum average good ratio
        for (let i = 0; i < n; i++) {
            avg = chocolates[i][0] / chocolates[i][1];
            ans += avg;
        }
 
        return ans / n;
    }
}
 
class Pair {
    constructor(diff, index) {
        this.diff = diff;
        this.index = index;
    }
}
 
class PriorityQueue {
    constructor(compare) {
        this.queue = [];
        this.compare = compare;
    }
 
    enqueue(item) {
        this.queue.push(item);
        this.queue.sort(this.compare);
    }
 
    dequeue() {
        if (this.isEmpty()) {
            return null;
        }
        return this.queue.shift();
    }
 
    isEmpty() {
        return this.queue.length === 0;
    }
}
 
// Driver code
const chocolates = [
    [1, 2],
    [3, 5],
    [4, 4]
];
 
const extraChocolates = 2;
 
// Function Call
console.log("Max Average Good Ratio: " +
MaximizeAverageGoodRatio.maximizeAverageGoodRatio(chocolates, extraChocolates).toFixed(4));
 
// This code is contributed by ragul21


Output

Max Average Good Ratio: 0.7833








Time Complexity: O(N*logN)
Auxiliary Space: O(N)



Like Article
Suggest improvement
Share your thoughts in the comments

Similar Reads