Skip to content

Commit 3b8c5df

Browse files
committed
feat: Add 0/1 Knapsack and its tabulation implementation with their corresponding tests
1 parent 31bf130 commit 3b8c5df

File tree

4 files changed

+201
-0
lines changed

4 files changed

+201
-0
lines changed
Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
package com.thealgorithms.dynamicprogramming;
2+
3+
/**
4+
* Class to solve the 0/1 Knapsack Problem using recursion.
5+
*
6+
* The 0/1 Knapsack problem is a classic dynamic programming problem
7+
* where we are given weights and values of `n` items. We need to put
8+
* these items in a knapsack of capacity `W` to get the maximum total value
9+
* in the knapsack. We can either include an item or exclude it — but cannot
10+
* include it more than once.
11+
*
12+
* Time Complexity: O(2^n) in worst case for the pure recursive approach (due to overlapping subproblems).
13+
* Using memoization or bottom-up dynamic programming reduces the time complexity to O(nW).
14+
*
15+
* Example:
16+
* val[] = {15, 14, 10, 45, 30}
17+
* wt[] = {2, 5, 1, 3, 4}
18+
* W = 7
19+
* Output: 75
20+
*/
21+
public class ZeroOneKnapsack {
22+
23+
/**
24+
* Solves the 0/1 Knapsack problem using recursion.
25+
*
26+
* @param val Array of item values (must have length at least n)
27+
* @param wt Array of item weights (must have length at least n)
28+
* @param W Total capacity of the knapsack
29+
* @param n Number of items to consider
30+
* @return The maximum value that can be obtained
31+
*/
32+
public static int knapsack(int[] val, int[] wt, int W, int n) {
33+
if (val == null || wt == null || val.length != wt.length) {
34+
throw new IllegalArgumentException("Value and weight arrays must be non-null and of equal length.");
35+
}
36+
if (W == 0 || n == 0) {
37+
return 0;
38+
}
39+
if (wt[n - 1] <= W) {
40+
// Include the current item
41+
int include = val[n - 1] + knapsack(val, wt, W - wt[n - 1], n - 1);
42+
// Exclude the current item
43+
int exclude = knapsack(val, wt, W, n - 1);
44+
return Math.max(include, exclude);
45+
} else {
46+
// Cannot include the item, move to next
47+
return knapsack(val, wt, W, n - 1);
48+
}
49+
}
50+
}
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
package com.thealgorithms.dynamicprogramming;
2+
3+
/**
4+
* Dynamic Programming approach for solving 0-1 Knapsack problem using tabulation.
5+
*
6+
* Problem Statement:
7+
* Given weights and values of n items, put these items in a knapsack of capacity W
8+
* to get the maximum total value in the knapsack. You cannot break an item.
9+
*
10+
* Time Complexity: O(n * W)
11+
* Space Complexity: O(n * W)
12+
*/
13+
public class ZeroOneKnapsackTab {
14+
15+
/**
16+
* Solves the 0-1 Knapsack problem using a tabulation approach (bottom-up DP).
17+
*
18+
* @param val The values of the items
19+
* @param wt The weights of the items
20+
* @param W The total capacity of the knapsack
21+
* @param n The number of items
22+
* @return The maximum value that can be put in a knapsack of capacity W
23+
*/
24+
public static int knapsackTab(int[] val, int[] wt, int W, int n) {
25+
int[][] dp = new int[n + 1][W + 1];
26+
27+
for (int i = 1; i <= n; i++) {
28+
int v = val[i - 1]; // value of current item
29+
int w = wt[i - 1]; // weight of current item
30+
for (int j = 1; j <= W; j++) {
31+
if (w <= j) {
32+
int include = v + dp[i - 1][j - w];
33+
int exclude = dp[i - 1][j];
34+
dp[i][j] = Math.max(include, exclude);
35+
} else {
36+
dp[i][j] = dp[i - 1][j];
37+
}
38+
}
39+
}
40+
return dp[n][W];
41+
}
42+
}
Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
package com.thealgorithms.dynamicprogramming;
2+
3+
import org.junit.jupiter.api.Test;
4+
import static org.junit.jupiter.api.Assertions.*;
5+
6+
/**
7+
* Unit tests for the ZeroOneKnapsackTab class.
8+
*/
9+
public class ZeroOneKnapsackTabTest {
10+
11+
/**
12+
* Test knapsackTab with a typical set of values and weights.
13+
* Checks if the maximum value for the given capacity is correct.
14+
*/
15+
@Test
16+
public void testKnapsackTab() {
17+
int[] val = {15, 14, 10, 45, 30};
18+
int[] wt = {2, 5, 1, 3, 4};
19+
int W = 7;
20+
int expected = 75;
21+
assertEquals(expected, ZeroOneKnapsackTab.knapsackTab(val, wt, W, val.length));
22+
}
23+
24+
/**
25+
* Test knapsackTab with empty arrays.
26+
* Should return 0 as there are no items to include.
27+
*/
28+
@Test
29+
public void testKnapsackTabEmpty() {
30+
int[] val = {};
31+
int[] wt = {};
32+
int W = 10;
33+
int expected = 0;
34+
assertEquals(expected, ZeroOneKnapsackTab.knapsackTab(val, wt, W, 0));
35+
}
36+
37+
/**
38+
* Test knapsackTab with zero capacity.
39+
* Should return 0 as no items can be included.
40+
*/
41+
@Test
42+
public void testKnapsackTabZeroCapacity() {
43+
int[] val = {10, 20, 30};
44+
int[] wt = {1, 1, 1};
45+
int W = 0;
46+
int expected = 0;
47+
assertEquals(expected, ZeroOneKnapsackTab.knapsackTab(val, wt, W, val.length));
48+
}
49+
}
Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
package com.thealgorithms.dynamicprogramming;
2+
3+
import static org.junit.jupiter.api.Assertions.assertEquals;
4+
import org.junit.jupiter.api.Test;
5+
6+
/**
7+
* Unit tests for the ZeroOneKnapsack algorithm.
8+
*/
9+
public class ZeroOneKnapsackTest {
10+
11+
/**
12+
* Test the knapsack algorithm with a basic example.
13+
*/
14+
@Test
15+
void testKnapsackBasic() {
16+
int[] val = {15, 14, 10, 45, 30};
17+
int[] wt = {2, 5, 1, 3, 4};
18+
int W = 7;
19+
int expected = 75;
20+
assertEquals(expected, ZeroOneKnapsack.knapsack(val, wt, W, val.length));
21+
}
22+
23+
/**
24+
* Test the knapsack algorithm when the knapsack capacity is zero.
25+
* Expected result is zero since nothing can be added.
26+
*/
27+
@Test
28+
void testZeroCapacity() {
29+
int[] val = {10, 20, 30};
30+
int[] wt = {1, 1, 1};
31+
int W = 0;
32+
int expected = 0;
33+
assertEquals(expected, ZeroOneKnapsack.knapsack(val, wt, W, val.length));
34+
}
35+
36+
/**
37+
* Test the knapsack algorithm when there are no items.
38+
* Expected result is zero since there is nothing to add.
39+
*/
40+
@Test
41+
void testNoItems() {
42+
int[] val = {};
43+
int[] wt = {};
44+
int W = 10;
45+
int expected = 0;
46+
assertEquals(expected, ZeroOneKnapsack.knapsack(val, wt, W, 0));
47+
}
48+
49+
/**
50+
* Test the knapsack algorithm with items that exactly fit the knapsack.
51+
*/
52+
@Test
53+
void testExactFit() {
54+
int[] val = {60, 100, 120};
55+
int[] wt = {10, 20, 30};
56+
int W = 50;
57+
int expected = 220;
58+
assertEquals(expected, ZeroOneKnapsack.knapsack(val, wt, W, val.length));
59+
}
60+
}

0 commit comments

Comments
 (0)