Distributing Blueberry Cheese Cake among Students
Last Updated :
13 Dec, 2023
There is a school in a village. It has N classes. One fine day, someone donated B blueberry cheesecakes to schools. Now you need to divide these cakes such that:
- Each class gets at least 1 cake.
- Each class will share the cake(s) among students.
- Your aim is to minimize the maximum number of students per cake in any class.
Examples:
Input: N = 1, B = 2, ClassList = 35
Output: 18
Explanation: The number of students in each cake will be 17 and 18, and the maximum of them is 18.
Input: N = 2, B = 7, ClassList = 20 50
Output: 10
Explanation: The number of cakes will be 2 for the first and 5 for the second class, so there will be a maximum of 10 students for each cake.
Source: Directi Interview | Set 8 (Off-Campus)
Basic Approach: The basic way to solve the problem is as follows:
- First, we will check whether is it possible to distribute at least 1 cake per class, distributing will not be possible only when the number of cakes is less than the number of classes, returning -1 in this scenario.
- After that we will distribute 1 cake per class, then we will find the class that has a maximum number of students per cake and give them an extra cake to minimize it, again repeat the same process until we have no cakes left.
- At the end, we will return the maximum number of students per cake among all classes.
Below is the implementation of the above idea.
C++
#include <bits/stdc++.h>
using namespace std;
int distribution( int n, int b, vector< float >& ClassList)
{
if (n > b) {
return -1;
}
vector< float > CakeList = ClassList;
vector< float > CakePerClass(n, 1);
b = b - n;
while (b > 0) {
b--;
int ind
= max_element(CakeList.begin(), CakeList.end())
- CakeList.begin();
CakeList[ind]
= ClassList[ind] / (CakePerClass[ind] + 1);
CakePerClass[ind]++;
}
return ceil (
*max_element(CakeList.begin(), CakeList.end()));
}
int main()
{
int N = 1;
int B = 2;
vector< float > ClassList
= { 35 };
cout << distribution(N, B, ClassList) << endl;
return 0;
}
|
Java
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
public class CakeDistribution {
public static int distribution( int n, int b, List<Float> classList) {
if (n > b) {
return - 1 ;
}
List<Float> cakeList = new ArrayList<>(classList);
List<Float> cakePerClass = new ArrayList<>(Collections.nCopies(n, 1 .0f));
b = b - n;
while (b > 0 ) {
b--;
int ind = cakeList.indexOf(Collections.max(cakeList));
cakeList.set(ind, classList.get(ind) / (cakePerClass.get(ind) + 1 ));
cakePerClass.set(ind, cakePerClass.get(ind) + 1 );
}
return ( int ) Math.ceil(Collections.max(cakeList));
}
public static void main(String[] args) {
int N = 1 ;
int B = 2 ;
List<Float> classList = new ArrayList<>();
classList.add( 35 .0f);
System.out.println(distribution(N, B, classList));
}
}
|
Python3
import math
def distribution(n, b, ClassList):
if n > b:
return - 1
CakeList = ClassList.copy()
CakePerClass = [ 1 for i in range (n)]
b = b - n
while b:
b - = 1
ind = CakeList.index( max (CakeList))
CakeList[ind] = ClassList[ind] / (CakePerClass[ind] + 1 )
CakePerClass[ind] + = 1
return math.ceil( max (CakeList))
N = 1
B = 2
ClassList = [ 35 ]
print (distribution(N, B, ClassList))
|
C#
using System;
using System.Collections.Generic;
using System.Linq;
public class GFG
{
public static int Distribution( int n, int b, List< float > classList)
{
if (n > b)
{
return -1;
}
List< float > cakeList = new List< float >(classList);
List< float > cakePerClass = Enumerable.Repeat(1.0f, n).ToList();
b = b - n;
while (b > 0)
{
b--;
int ind = cakeList.IndexOf(cakeList.Max());
cakeList[ind] = classList[ind] / (cakePerClass[ind] + 1);
cakePerClass[ind] += 1;
}
return ( int )Math.Ceiling(cakeList.Max());
}
public static void Main( string [] args)
{
int N = 1;
int B = 2;
List< float > classList = new List< float >();
classList.Add(35.0f);
Console.WriteLine(Distribution(N, B, classList));
}
}
|
Javascript
function distribution(n, b, classList) {
if (n > b) {
return -1;
}
let cakeList = [...classList];
let cakePerClass = new Array(n).fill(1);
b = b - n;
while (b > 0) {
b--;
let ind = cakeList.indexOf(Math.max(...cakeList));
cakeList[ind] = classList[ind] / (cakePerClass[ind] + 1);
cakePerClass[ind]++;
}
return Math.ceil(Math.max(...cakeList));
}
const N = 1;
const B = 2;
const ClassList = [35];
console.log(distribution(N, B, ClassList));
|
Time Complexity: O(N * B),
Auxiliary Space: O(N), where N is number of classes and B is number of blueberry cakes.
Efficient Approach: To solve the problem using Binary Search follow the below idea:
Instead of distributing cakes one by one, we can set a value for the “maximum students per cake” and then check if it’s possible to distribute the cakes in a way that meets this value. If we can achieve this distribution, we’ll increase the “maximum students per cake” and try again. Conversely, if we can’t achieve the desired distribution, we’ll decrease the “maximum students per cake” and attempt to find a feasible distribution.
- To do this we can use Binary Search by setting lower bound l to 1 as in the best case scenario we are able to distribute 1 cake per child, and upper bound r to maximum student count among classes as in the worst case scenario we will have to distribute 1 cake per class.
- Now In each iteration we will find a mid and then calculate the total number of cakes required and change the upper or lower bound accordingly.
- To calculate the total number of cakes required for the current mid value, iterate through each ClassList and determine how many cakes are needed to accommodate the students in that class while ensuring that each cake can have at most mid students. Sum up these calculations to obtain the total cakes required.
Below is the implementation of the above idea.
C++
#include <bits/stdc++.h>
using namespace std;
int EfficientDistribution( int n, int b,
vector< int >& ClassList)
{
int l = 1;
int r
= *max_element(ClassList.begin(), ClassList.end());
if (b < n) {
return -1;
}
while (l < r) {
int mid = (l + r) / 2;
int cakes_req = 0;
for ( int i = 0; i < n; i++) {
cakes_req += ceil (( float )ClassList[i] / mid);
}
if (cakes_req <= b) {
r = mid;
}
else {
l = mid + 1;
}
}
return r;
}
int main()
{
int N = 1;
int B = 2;
vector< int > ClassList
= { 35 };
cout << EfficientDistribution(N, B, ClassList) << endl;
return 0;
}
|
Java
import java.util.ArrayList;
import java.util.Collections;
public class GFG {
static int efficientDistribution( int n, int b, ArrayList<Integer> classList) {
int l = 1 ;
int r = Collections.max(classList);
if (b < n) {
return - 1 ;
}
while (l < r) {
int mid = (l + r) / 2 ;
int cakesReq = 0 ;
for ( int i = 0 ; i < n; i++) {
cakesReq += Math.ceil(( double ) classList.get(i) / mid);
}
if (cakesReq <= b) {
r = mid;
} else {
l = mid + 1 ;
}
}
return r;
}
public static void main(String[] args) {
int N = 1 ;
int B = 2 ;
ArrayList<Integer> classList = new ArrayList<>();
classList.add( 35 );
System.out.println(efficientDistribution(N, B, classList));
}
}
|
Python3
import math
def EfficientDistribution(n, b, ClassList):
l = 1
r = max (ClassList)
if b < n:
return "-1"
while l < r:
mid = (l + r) / / 2
cakes_req = 0
for i in range (n):
cakes_req + = math.ceil(ClassList[i] / mid)
if cakes_req < = b:
r = mid
else :
l = mid + 1
return r
N = 1
B = 2
ClassList = [ 35 ]
print (EfficientDistribution(N, B, ClassList))
|
C#
using System;
using System.Collections.Generic;
using System.Linq;
class Program
{
static int EfficientDistribution( int n, int b, List< int > classList)
{
int l = 1;
int r = classList.Max();
if (b < n)
{
return -1;
}
while (l < r)
{
int mid = (l + r) / 2;
int cakesReq = 0;
foreach ( int students in classList)
{
cakesReq += ( int )Math.Ceiling(( double )students / mid);
}
if (cakesReq <= b)
{
r = mid;
}
else
{
l = mid + 1;
}
}
return r;
}
static void Main()
{
int N = 1;
int B = 2;
List< int > classList = new List< int > { 35 };
Console.WriteLine(EfficientDistribution(N, B, classList));
}
}
|
Javascript
function EfficientDistribution(n, b, ClassList) {
let l = 1;
let r = ClassList.reduce((a, b) => Math.max(a, b), -Infinity);
if (b < n) {
return -1;
}
while (l < r) {
let mid = Math.trunc((l + r) / 2);
let cakes_req = 0;
for (let i = 0; i < n; i++) {
cakes_req += Math.ceil(ClassList[i] / mid);
}
if (cakes_req <= b) {
r = mid;
} else {
l = mid + 1;
}
}
return r;
}
let N = 1;
let B = 2;
let ClassList = [35];
console.log(EfficientDistribution(N, B, ClassList));
|
Time Complexity: O(N * log R),
Auxiliary Space: O(N), where N is number of classes and R is maximum student count among classes.
Share your thoughts in the comments
Please Login to comment...