Juice Bottling
Juice Bottling
Category
Dynamic Programming
Difficulty
Hard
Problem Statement
You have n units of juice and an array prices where prices[i] is the revenue obtained by selling a bottle containing exactly i units of juice (prices[0] = 0). Determine how to divide the n units into bottles to maximize total revenue. Return the bottle sizes used.
Intuition
This is the classic rod cutting problem applied to juice. For n units of juice, we choose a first bottle of size k (earning prices[k]) and then optimally bottle the remaining n - k units. Overlapping subproblems arise because multiple first-cut choices lead to the same remaining quantity.
Approach
- Create an array
dpof sizen+1, wheredp[i]is the maximum revenue fromiunits. Setdp[0] = 0. - Create a
cutsarray to reconstruct the solution. - For each quantity
ifrom 1 ton:- For each bottle size
kfrom 1 toi:- If
prices[k] + dp[i-k] > dp[i]:- Update
dp[i] = prices[k] + dp[i-k] - Record
cuts[i] = k
- Update
- If
- For each bottle size
- Backtrack from
cuts[n]to build the list of bottle sizes. - Return the list.
Pseudocode
function juiceBottling(prices):
n = length(prices) - 1
dp = array of size (n+1), filled with 0
cuts = array of size (n+1), filled with 0
for i from 1 to n:
for k from 1 to i:
if prices[k] + dp[i-k] > dp[i]:
dp[i] = prices[k] + dp[i-k]
cuts[i] = k
// Reconstruct bottle sizes
bottles = []
remaining = n
while remaining > 0:
bottles.append(cuts[remaining])
remaining -= cuts[remaining]
return bottles
Time & Space Complexity
| Measure | Complexity | Justification |
|---|---|---|
| Time | O(n^2) | Two nested loops: for each of n quantities, try up to n bottle sizes |
| Space | O(n) | DP array and cuts array |
Key Insights
- This is structurally identical to the rod cutting problem. The "price per unit length" framing is the same as "price per bottle size."
- Greedy (e.g., always pick the bottle with the best price-per-unit) does not work because combinations of smaller bottles may out-earn larger ones.
- If
prices[n] >= dp[n]for all possible decompositions, a single bottle of sizenis optimal — but this must be discovered by DP, not assumed. - The problem can also be solved top-down with memoization; the recurrence is
dp[i] = max over k of (prices[k] + dp[i-k]).
Edge Cases
- n = 0: no juice to bottle; revenue is 0, return an empty list.
- All prices are 0 except
prices[1]: sell all juice in unit-size bottles. prices[n]is the highest: one bottle of sizenis optimal.- Prices decrease per unit for larger bottles: smaller bottles are always preferred; the DP discovers this.
- n = 1: the only option is a single bottle of size 1.