Unbounded Knapsack Problem in DSA C++ - Time & Space Complexity
We want to understand how the time needed to solve the Unbounded Knapsack problem grows as the input size changes.
Specifically, how the number of items and the knapsack capacity affect the work done.
Analyze the time complexity of the following code snippet.
int unboundedKnapsack(int W, int n, int val[], int wt[]) {
int dp[W+1] = {0};
for (int i = 0; i <= W; i++) {
for (int j = 0; j < n; j++) {
if (wt[j] <= i) {
dp[i] = std::max(dp[i], dp[i - wt[j]] + val[j]);
}
}
}
return dp[W];
}
This code finds the maximum value for a knapsack of capacity W using unlimited copies of n items.
Identify the loops, recursion, array traversals that repeat.
- Primary operation: Nested loops where the outer loop runs from 0 to W and the inner loop runs over all n items.
- How many times: Outer loop runs W+1 times, inner loop runs n times for each outer iteration, so total roughly (W+1)*n times.
As the knapsack capacity W grows, the outer loop runs more times. For each capacity, we check all n items.
| Input Size (W) | Approx. Operations (W * n) |
|---|---|
| 10 | 10 * n |
| 100 | 100 * n |
| 1000 | 1000 * n |
Pattern observation: The work grows linearly with both the knapsack capacity and the number of items.
Time Complexity: O(W * n)
This means the time needed grows proportionally to the product of the knapsack capacity and the number of items.
[X] Wrong: "The time complexity is exponential because we can pick unlimited items."
[OK] Correct: The dynamic programming approach avoids repeated work by storing results for each capacity, so it runs in polynomial time, not exponential.
Understanding this time complexity helps you explain how dynamic programming improves efficiency over naive methods, a key skill in problem solving.
"What if we changed the problem to allow only one copy of each item? How would the time complexity change?"
Practice
Solution
Step 1: Understand item usage rules
In 0/1 Knapsack, each item can be chosen at most once. In Unbounded Knapsack, items can be chosen unlimited times.Step 2: Compare problem definitions
Unbounded Knapsack allows multiple copies of the same item, unlike 0/1 Knapsack.Final Answer:
In Unbounded Knapsack, you can use unlimited copies of each item. -> Option BQuick Check:
Unbounded Knapsack = unlimited item usage [OK]
- Confusing 0/1 Knapsack with Unbounded Knapsack
- Thinking items cannot repeat in Unbounded Knapsack
- Assuming both problems have same constraints
Solution
Step 1: Understand DP array role
DP array stores max value for weights from 0 to W. It should start with 0 for no items chosen.Step 2: Choose correct initialization
Filling dp with 0 means no value at start, which is correct. int dp[W+1]; fill(dp, dp+W+1, 0); uses fill with 0 correctly.Final Answer:
int dp[W+1]; fill(dp, dp+W+1, 0); -> Option AQuick Check:
DP array initialized to 0 for all weights [OK]
- Leaving dp uninitialized causing garbage values
- Initializing dp with -1 which is incorrect here
- Using wrong array size causing out-of-bound errors
int weights[] = {2, 3};
int values[] = {10, 15};
int W = 5;
int dp[6] = {0};
for (int i = 0; i <= W; i++) {
for (int j = 0; j < 2; j++) {
if (weights[j] <= i) {
dp[i] = max(dp[i], dp[i - weights[j]] + values[j]);
}
}
}
std::cout << dp[W] << std::endl;Solution
Step 1: Trace dp array updates for weights 0 to 5
Calculate dp[i]: dp[0]=0 For i=1: dp[1]=0 (no items fit) For i=2: dp[2]=max(dp[2], dp[0]+10)=10 For i=3: dp[3]=max(dp[3], dp[0]+15)=15 For i=4: dp[4]=max(dp[4], dp[2]+10=20, dp[1]+15=15)=20 For i=5: dp[5]=max(dp[5], dp[3]+10=25, dp[2]+15=25) so dp[5]=25Step 2: Confirm final dp[5] value
Maximum value for weight 5 is 25 by choosing items (3 + 2) or (2 + 3).Final Answer:
25 -> Option CQuick Check:
Max value at W=5 is 25 [OK]
- Adding values incorrectly for dp updates
- Ignoring multiple item usage possibilities
- Mixing up indices in dp array
int dp[W+1];
for (int i = 0; i <= W; i++) {
for (int j = 0; j < n; j++) {
if (weights[j] <= i) {
dp[i] = max(dp[i], dp[i - weights[j]] + values[j]);
}
}
}Solution
Step 1: Check dp array initialization
dp array is declared but not initialized, so it contains garbage values affecting max calculations.Step 2: Importance of initializing dp
dp should be initialized to 0 for all indices before the loops to ensure correct max value updates.Final Answer:
dp array is not initialized before use. -> Option AQuick Check:
Uninitialized dp causes wrong results [OK]
- Forgetting to initialize dp array
- Assuming dp defaults to zero
- Ignoring garbage values in dp
Solution
Step 1: Calculate dp values from 0 to 7
dp[0]=0 For i=1: dp[1]=max(0, dp[0]+15)=15 For i=2: dp[2]=max(0, dp[1]+15)=30 For i=3: dp[3]=max(0, dp[0]+50, dp[2]+15)=50 For i=4: dp[4]=max(0, dp[1]+50, dp[0]+60, dp[3]+15)=65 For i=5: dp[5]=max(0, dp[2]+50, dp[1]+60, dp[4]+15)=80 For i=6: dp[6]=max(0, dp[3]+50, dp[2]+60, dp[5]+15)=100 For i=7: dp[7]=max(0, dp[4]+50=115, dp[3]+60=110, dp[6]+15=115)=115Step 2: Confirm maximum value at W=7
The maximum value achievable is 115 by combining items optimally.Final Answer:
115 -> Option DQuick Check:
Max value at W=7 is 115 [OK]
- Not considering all item combinations
- Incorrect dp updates for each weight
- Mixing up weights and values indices
Ready to prove it?
Pass the test and this pattern moves unknown
