CMD Guide
HomeDSADynamic Programming

Unbounded Knapsack

Unbounded knapsack maximizes profit by choosing, for each capacity from 1 up to C, whether re-using an already-solved smaller-capacity answer (allowing the current item to be picked again) beats leaving that capacity's best answer alone — because an item can be reused, the recurrence reduces capacity but never removes the item from consideration.

Recognize the pattern

Brute force → optimal

Brute force: recursion trying, at every capacity, either skip item i or take item i and recurse on capacity - weight[i] while staying on the same item index i (not i-1, since reuse is allowed). Without memoization this branches into overlapping subproblems: T(C) = T(C-w) + T(C) style calls repeat the same (i, capacity) pairs exponentially — O(2^C) in the worst case, O(C) space for the call stack.

Optimal: bottom-up DP over a 1-D array dp[0..C], since each item may repeat, we deliberately let dp[cap] reuse a value just written in the same pass (unlike 0/1 knapsack, which must iterate capacity in reverse to forbid reuse). Iterate capacity forward: dp[cap] = max(dp[cap], dp[cap-weight[i]] + profit[i]).

Complexity, derived

Two nested loops: for each of the N item types, for each capacity 1..C we do O(1) work (one comparison, one addition). Total operations = N × C ⇒ time O(N·C). Space: one dp array of size C+1 ⇒ O(C) (no per-item row needed because forward iteration already permits reuse within the same item's row, and rows across items only ever improve dp monotonically, so a single rolling array suffices). Brute force without memo redoes each (item-index, capacity) combination up to C times per level — recurrence R(C) = R(C-1) + R(C-2) + ... in the worst case gives exponential blowup, i.e., O(2^C) time, O(C) stack space.

Worked example

Weights {1,2,3}, Profits {15,20,50}, Capacity 5. dp[0..5] starts at 0. Process item Apple (w=1,p=15) forward:

cap012345
after Apple01530456075
after Orange(w2,p20)01530456075
after Melon(w3,p50)01530506580

At cap=5 during Melon's pass: dp[5] = max(dp[5]=75, dp[5-3]+50 = dp[2]+50 = 30+50 = 80) → 80, matching "2 Apples + 1 Melon".

Java

int unboundedKnapsack(int[] weights, int[] profits, int capacity) {
    int n = weights.length;
    int[] dp = new int[capacity + 1];
    for (int i = 0; i < n; i++) {
        for (int cap = weights[i]; cap <= capacity; cap++) { // forward!
            dp[cap] = Math.max(dp[cap], dp[cap - weights[i]] + profits[i]);
        }
    }
    return dp[capacity];
}

Pitfalls

When to use / when NOT — trade-offs

Use unbounded knapsack DP when items are reusable and you need the true optimum over all repeat-combinations in O(N·C) time/O(C) space — far better than the brute-force exponential enumeration. Do NOT use it if items are limited-supply (each has a count k) — that's bounded knapsack, solved by binary/log splitting each item into 0/1 items (O(N·C·log k)) or a monotonic-deque optimization. If C is huge (e.g., 10^9) but N is small and weights are small, unbounded knapsack DP is infeasible; consider a greedy/number-theory approach (Chicken McNugget / Frobenius, or meet-in-the-middle for the residues) instead.

Takeaways

Recall: Why does making the capacity loop go forward (instead of backward) let the same item be used more than once?


Adapted from the classic "Unbounded Knapsack" formulation (Educative-style DP course material); complexity and forward/backward loop-direction analysis derived from first principles for this guide.

🤖 Don't fully get this? Learn it with Claude

Stuck on Unbounded Knapsack? Open Claude, copy a block below, and it'll teach you this exact concept — visually and interactively.

🎨 Explain it visually

Build the mental picture, not memorization.

I just read a lesson on **Unbounded Knapsack** (DSA) and want to truly understand it. Explain Unbounded Knapsack from first principles using ONE vivid real-world analogy and a visual mental model — draw it as ASCII art or a clear step-by-step diagram — with a concrete example using real numbers. Then ask me one question to check I got the mental picture, and wait for my reply. If you're unsure or a claim isn't standard, say so and reason from first principles instead of guessing.
🤔 Walk me through it (interactive)

Socratic — adapts to where you're stuck.

Teach me **Unbounded Knapsack** interactively. Ask me ONE guiding question at a time, wait for my answer, and adapt to my confusion — build the idea with me step by step instead of explaining it all at once. If you're unsure or a claim isn't standard, say so and reason from first principles instead of guessing.
🧪 Quiz me & fix my gaps

Active recall exposes what you missed.

Quiz me on **Unbounded Knapsack** with 5 questions, easy to tricky, ONE at a time. Tell me if each answer is right; at the end, explain clearly what I got wrong and why. If you're unsure or a claim isn't standard, say so and reason from first principles instead of guessing.
🧠 Make it stick

Intuition + hook + flashcards for long-term memory.

Help me remember **Unbounded Knapsack** for the long term: give the one-sentence intuition, a memorable hook/mnemonic, a tiny worked example, and 3 active-recall flashcards (Q -> A). If you're unsure or a claim isn't standard, say so and reason from first principles instead of guessing.

📝 My notes