AlgoMaster Logo

Fair Distribution of Cookies

Last Updated: April 2, 2026

medium
5 min read

Understanding the Problem

We have some bags of cookies and some children. Every bag must be given to exactly one child (no splitting bags), and we want to minimize the maximum total any single child receives. In other words, we want the most "fair" distribution, where fairness is measured by how heavy the most-loaded child's pile is.

This is fundamentally an assignment problem. Each bag must go to one of k children, and we want the assignment that minimizes the maximum sum across all children. Think of it like partitioning the array into k groups to minimize the maximum group sum.

The key observation is that cookies.length is at most 8. That's a tiny search space. Each of the n bags can be assigned to any of the k children, giving us k^n total assignments. With k and n both at most 8, the worst case is 8^8 = about 16.7 million, which is manageable with backtracking and pruning.

Key Constraints:

  • 2 <= cookies.length <= 8 -> With at most 8 bags, exponential approaches like backtracking through all assignments (k^n) are perfectly feasible. Even 8^8 ~ 16.7 million is well within time limits.
  • 1 <= cookies[i] <= 10^5 -> Cookie counts are positive, so every child who gets at least one bag will have a positive total. The maximum possible total for one child is 8 * 10^5 = 800,000.
  • 2 <= k <= cookies.length -> There are at least as many bags as children, so it's always possible to give each child at least one bag.

Approach 1: Brute Force Backtracking

Intuition

The most natural approach: for each bag of cookies, try assigning it to each of the k children. Once all bags are assigned, compute the maximum total across all children and track the minimum.

Since each of the n bags can go to any of k children, there are k^n total assignments. With n = 8 and k = 8 in the worst case, that's 8^8 = 16,777,216 assignments. That's a lot, but it's within the range of what a computer can handle in a couple of seconds.

We use a simple recursive approach: process bags one at a time, and for each bag, try giving it to each child. When we've assigned all bags, we record the unfairness (the max of all children's totals) if it's better than what we've seen so far.

Algorithm

  1. Create an array children of size k, initialized to zeros, to track each child's current cookie total.
  2. Recursively process bags from index 0 to n-1.
  3. For each bag, try assigning it to each of the k children by adding cookies[i] to that child's total.
  4. After assigning, recurse to the next bag. After returning, undo the assignment (backtrack).
  5. When all bags are assigned, compute the maximum value in children and update the global minimum if it's lower.
  6. Return the global minimum.

Example Walkthrough

Input:

0
8
1
15
2
10
3
20
4
8
cookies
2
k

We try every possible assignment of 5 bags to 2 children. For example, giving all bags to Child 0 yields max = 61. Giving [8,15,8] to Child 0 and [10,20] to Child 1 yields max(31, 30) = 31. Among all k^n = 32 assignments, the minimum unfairness is 31.

Code

The brute force tries every assignment, but many are redundant. If multiple children have the same total, assigning a bag to any of them is equivalent. What if we skipped redundant assignments and pruned hopeless branches early?

Approach 2: Backtracking with Pruning

Intuition

The brute force works but does a lot of unnecessary work. Two key observations let us prune the search tree dramatically:

  1. Upper bound pruning. If any child's current total already meets or exceeds our best known answer, there's no point continuing down this path. The unfairness can only get worse as we assign more bags.
  1. Symmetry breaking. If multiple children currently have the same total (especially zero), assigning the current bag to any one of them is equivalent. We only need to try one representative. This is a huge optimization because at the start of the recursion, all k children have zero cookies. Without this pruning, we'd explore k identical branches at the first level.

There's a third useful optimization: sorting the cookies array in descending order. By assigning the largest bags first, we reach higher totals sooner, which triggers the upper bound pruning earlier and cuts off more branches.

Algorithm

  1. Sort cookies in descending order (largest bags first for earlier pruning).
  2. Create an array children of size k, initialized to zeros.
  3. Maintain a global result initialized to the total sum of all cookies.
  4. Recursively assign bags starting from index 0.
  5. At each step, for each child, assign the current bag only if adding this bag doesn't make the child's total >= current best result (upper bound pruning), and this child is the first one with this particular total value (symmetry breaking).
  6. After assigning, recurse to the next bag, then backtrack.
  7. When all bags are assigned, update the result with the maximum child total.

Example Walkthrough

1Start: sorted cookies = [20,15,10,8,8], children = [0,0], result = 61
0
20
bag
1
15
2
10
3
8
4
8
1/8
1children = [0, 0], result = 61
0
0
C0
1
0
C1
1/8

Code

The backtracking with pruning is fast enough for these constraints, but there's a fundamentally different approach using bitmask DP that gives a cleaner complexity guarantee.

Approach 3: Bitmask Dynamic Programming

Intuition

Instead of assigning bags to children one at a time, we represent which bags have been assigned using a bitmask. If there are n bags, a bitmask of n bits can represent any subset. Bit i being set means bag i has been assigned.

First, precompute the sum of cookies for every possible subset (all 2^n subsets). Then define dp[j][mask] as the minimum unfairness when distributing the bags in mask among the first j children. For each child, we try every possible subset of the remaining bags to give them, and take the minimum over all valid partitions.

This approach has a clean O(k * 3^n) complexity because for each mask, iterating over all subsets of that mask across all masks totals 3^n (by the inclusion-exclusion principle: each element is in the outer mask, in the inner subset, or in neither).

Algorithm

  1. Precompute subsetSum[mask] for all 2^n masks, where each mask represents a subset of bags.
  2. Initialize dp[0][0] = 0 (zero children assigned, no bags distributed, unfairness is 0) and everything else to infinity.
  3. For each child j from 1 to k, for each mask, enumerate all subsets sub of mask and compute dp[j][mask] = min(dp[j][mask], max(dp[j-1][mask ^ sub], subsetSum[sub])).
  4. Return dp[k][(1 << n) - 1] (all k children assigned, all bags distributed).

Example Walkthrough

1Precomputed subsetSum for all 2^3=8 masks. Index = bitmask of bags.
0
0
000:{}
1
8
001:{8}
2
15
010:{15}
3
23
011:{8,15}
4
10
5
18
6
25
7
33
1/6

Code