Knapsack with Duplicate Items
Keep one row: dp[c] is the best value that fits in capacity c using the items seen so far. For each item, go over c from the item's weight up to the capacity, low → high. When we reach c, the cell dp[c − w] was already updated for this item, so it may already hold a copy of it. That is what lets the item repeat.
After each pass, dp[c] is the best value that fits in capacity c using the items so far, and this holds because dp[c − w] may already include a copy of the current item, which is exactly the repeat we want.
Problem
You have a bag that can hold a total weight of capacity. You also have n kinds of items. Item i has a weight wt[i] and a value val[i].
You may take the same kind of item as many times as you like. Find the biggest total value you can pack without going over the capacity.
The function returns that biggest total value. It does not need to say which items were taken.
Two lists val and wt of the same length n (the value and weight of each kind of item), and the integer capacity.
One number: the largest total value of a set of items (repeats allowed) whose total weight is at most capacity.
Take item A twice (weight 4, value 10) and item B once (weight 3, value 7). The weight is 7 and the value is 17. No other mix that fits is worth more.
Take the item with weight 3 (value 40) and the item with weight 5 (value 70). The weight is 8 and the value is 110.
Take the weight-1 item three times: weight 3, value 3.
- • 1 ≤ capacity, val.size() ≤ 1000
- • 1 ≤ val[i], wt[i] ≤ 100
- • wt.size() = val.size()
First, think yourself
Before opening any solution, try to answer these on paper. Use hints only when stuck — each hint is counted.
- 1.
Can I take the same kind of item more than once here? How does that change what a single decision looks like?
- 2.
If I already know the best value for a smaller bag, how could it help me with a bigger bag?
- 3.
For one capacity, which choices do I have for the item I am looking at right now?
- 4.
If I fill the bag from the smallest capacity to the biggest, which cells already hold a new value when I read them?
- 5.
How many (item, capacity) pairs are there, and how many calls would a recursion make for them?
Brute force approach
Better approach
Optimized approach
Why does this algorithm work?
Dry run
All approaches compared
| Approach | Idea | Time | Space |
|---|---|---|---|
| Brute Force | Recurse over the items: skip each one, or take one copy and stay on it. No memory. | O(2^(N + W)) | O(N + W) |
| Better | dp[i][c] = best value using the first i items with room c; each cell is worked out once | O(N · W) | O(N · W) |
| Optimal | One array dp[c]; for each item, go over c from its weight up to capacity | O(N · W) | O(W) |
Why does this belong to this pattern?
- “you may take the same item as many times as you like”Items can repeat, so this is the unbounded knapsack. The capacity loop goes low → high.
- “total weight is at most the capacity”The bag has room c, so the table is indexed by capacity.
- “biggest total value”Keep the best of the choices: skip the item, or add one more copy of it.
This is the anchor of the unbounded sub-pattern. The only change from 0/1 knapsack is the loop direction. 0/1 goes capacity high → low, so each item is read from the old row and can be used once. Unbounded goes low → high, so the item can be read from the row it is building. Its neighbours keep this idea, but change what a cell means (Coin Change) or the loop order (Coin Change II and Combination Sum IV).
Don't make this mistake
High → low makes dp[c − w] still hold the value from before this item, so each item is used at most once. On the dry run (A = weight 2 value 5, B = weight 3 value 7, capacity 7), the high → low loop gives dp[7] = 12, which is A once plus B once. The correct answer is 17: A twice plus B once.
Overwriting throws away the best value found so far. On the dry run, item B at capacity 4 would replace dp[4] = 10 with 7, and the final answer would be 14 instead of 17.
For any c smaller than the weight, c − wt[i] is negative, so the code reads before the start of the array. Start at the item's weight.
Want to implement this?
Write it yourself on GeeksforGeeks, then come back and compare your code with the solutions above.
Open coding workspaceHow this concept connects to System Design & C++ Systems
Top engineering interviews test whether you understand how algorithms like DP — Knapsack translate into production architectures and low-level memory mechanics.
Foundations: Object-Oriented Principles in C++23
Class invariants, pure virtual interfaces, and RAII smart pointers.
Food Delivery System (Zomato Architecture)
Real-world machine coding application of algorithms and design patterns.
Pointers vs References Deep Dive
Pointer arithmetic and memory layout under the hood.
Virtual Method Table (vtable) & Memory Layout
Polymorphism, vptr overhead, and multiple inheritance in memory.