diff --git a/src/main/java/com/thealgorithms/dynamicprogramming/ZeroOneKnapsack.java b/src/main/java/com/thealgorithms/dynamicprogramming/ZeroOneKnapsack.java new file mode 100644 index 000000000000..3c29e30d625a --- /dev/null +++ b/src/main/java/com/thealgorithms/dynamicprogramming/ZeroOneKnapsack.java @@ -0,0 +1,38 @@ +package com.thealgorithms.dynamicprogramming; + +/** + * The {@code ZeroOneKnapsack} class provides a method to solve the classic 0/1 Knapsack problem. + * It returns the maximum value that can be obtained by selecting items within the weight limit. + * + * Problem Description: Given weights and values of n items, put these items in a knapsack of capacity W + * such that the total value is maximized. You cannot break an item, either pick the complete item or don't pick it. + * + * https://en.wikipedia.org/wiki/Knapsack_problem + */ +public final class ZeroOneKnapsack { + private ZeroOneKnapsack() { + } + + /** + * Solves the 0/1 Knapsack problem using recursion. + * + * @param values the array containing values of the items + * @param weights the array containing weights of the items + * @param capacity the total capacity of the knapsack + * @param n the number of items + * @return the maximum total value achievable within the given weight limit + */ + public static int compute(int[] values, int[] weights, int capacity, int n) { + if (n == 0 || capacity == 0) { + return 0; + } + + if (weights[n - 1] <= capacity) { + int include = values[n - 1] + compute(values, weights, capacity - weights[n - 1], n - 1); + int exclude = compute(values, weights, capacity, n - 1); + return Math.max(include, exclude); + } else { + return compute(values, weights, capacity, n - 1); + } + } +} diff --git a/src/main/java/com/thealgorithms/dynamicprogramming/ZeroOneKnapsackTab.java b/src/main/java/com/thealgorithms/dynamicprogramming/ZeroOneKnapsackTab.java new file mode 100644 index 000000000000..d2b1c18db11b --- /dev/null +++ b/src/main/java/com/thealgorithms/dynamicprogramming/ZeroOneKnapsackTab.java @@ -0,0 +1,49 @@ +package com.thealgorithms.dynamicprogramming; + +/** + * The {@code ZeroOneKnapsackTab} class provides a method to solve the 0-1 Knapsack problem + * using dynamic programming (tabulation approach). + * + *

0-1 Knapsack Problem - + * Given weights and values of n items, and a maximum weight W, + * determine the maximum total value of items that can be included in the knapsack + * such that their total weight does not exceed W. Each item can be picked only once. + * + * Problem Link: https://www.geeksforgeeks.org/0-1-knapsack-problem-dp-10/ + */ +public final class ZeroOneKnapsackTab { + + private ZeroOneKnapsackTab() { + // prevent instantiation + } + + /** + * Solves the 0-1 Knapsack problem using the bottom-up tabulation technique. + * + * @param val the values of the items + * @param wt the weights of the items + * @param W the total capacity of the knapsack + * @param n the number of items + * @return the maximum value that can be put in the knapsack + */ + public static int compute(int[] val, int[] wt, int W, int n) { + int[][] dp = new int[n + 1][W + 1]; + + for (int i = 1; i <= n; i++) { + int value = val[i - 1]; + int weight = wt[i - 1]; + + for (int w = 1; w <= W; w++) { + if (weight <= w) { + int include = value + dp[i - 1][w - weight]; + int exclude = dp[i - 1][w]; + dp[i][w] = Math.max(include, exclude); + } else { + dp[i][w] = dp[i - 1][w]; + } + } + } + + return dp[n][W]; + } +} diff --git a/src/test/java/com/thealgorithms/dynamicprogramming/ZeroOneKnapsackTabTest.java b/src/test/java/com/thealgorithms/dynamicprogramming/ZeroOneKnapsackTabTest.java new file mode 100644 index 000000000000..9f011ade695e --- /dev/null +++ b/src/test/java/com/thealgorithms/dynamicprogramming/ZeroOneKnapsackTabTest.java @@ -0,0 +1,58 @@ +package com.thealgorithms.dynamicprogramming; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +import org.junit.jupiter.api.Test; + +/** + * Test class for {@code ZeroOneKnapsackTab}. + */ +public class ZeroOneknapsackTabTest { + + /** + * Tests the 0-1 Knapsack tabulation approach with known values. + */ + @Test + public void testKnownValues() { + int[] val = {60, 100, 120}; + int[] wt = {10, 20, 30}; + int W = 50; + int n = val.length; + + // Expected result is 220 (items with weight 20 and 30) + assertEquals(220, ZeroOneKnapsackTab.compute(val, wt, W, n), "Maximum value for capacity 50 should be 220."); + } + + @Test + public void testZeroCapacity() { + int[] val = {10, 20, 30}; + int[] wt = {1, 1, 1}; + int W = 0; + int n = val.length; + + // With zero capacity, the result should be 0 + assertEquals(0, ZeroOneKnapsackTab.compute(val, wt, W, n), "Maximum value for capacity 0 should be 0."); + } + + @Test + public void testZeroItems() { + int[] val = {}; + int[] wt = {}; + int W = 10; + int n = val.length; + + // With no items, the result should be 0 + assertEquals(0, ZeroOneKnapsackTab.compute(val, wt, W, n), "Maximum value with no items should be 0."); + } + + @Test + public void testExactFit() { + int[] val = {5, 10, 15}; + int[] wt = {1, 2, 3}; + int W = 6; + int n = val.length; + + // All items fit exactly into capacity 6 + assertEquals(30, ZeroOneKnapsackTab.compute(val, wt, W, n), "Maximum value for exact fit should be 30."); + } +} diff --git a/src/test/java/com/thealgorithms/dynamicprogramming/ZeroOneKnapsackTest.java b/src/test/java/com/thealgorithms/dynamicprogramming/ZeroOneKnapsackTest.java new file mode 100644 index 000000000000..285524bb77da --- /dev/null +++ b/src/test/java/com/thealgorithms/dynamicprogramming/ZeroOneKnapsackTest.java @@ -0,0 +1,55 @@ +package com.thealgorithms.dynamicprogramming; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +import org.junit.jupiter.api.Test; + +/** + * Test class for {@code ZeroOneKnapsack}. + */ +public class ZeroOneKnapsackTest { + + /** + * Tests the knapsack computation for a basic example. + */ + @Test + public void testKnapsackBasic() { + int[] val = {15, 14, 10, 45, 30}; + int[] wt = {2, 5, 1, 3, 4}; + int W = 7; + assertEquals(75, ZeroOneKnapsack.compute(val, wt, W, val.length), "Expected maximum value is 75."); + } + + /** + * Tests the knapsack computation when the knapsack capacity is zero. + */ + @Test + public void testZeroCapacity() { + int[] val = {10, 20, 30}; + int[] wt = {1, 1, 1}; + int W = 0; + assertEquals(0, ZeroOneKnapsack.compute(val, wt, W, val.length), "Expected maximum value is 0 for zero capacity."); + } + + /** + * Tests the knapsack computation when there are no items. + */ + @Test + public void testNoItems() { + int[] val = {}; + int[] wt = {}; + int W = 10; + assertEquals(0, ZeroOneKnapsack.compute(val, wt, W, 0), "Expected maximum value is 0 when no items are available."); + } + + /** + * Tests the knapsack computation when items exactly fit the capacity. + */ + @Test + public void testExactFit() { + int[] val = {60, 100, 120}; + int[] wt = {10, 20, 30}; + int W = 50; + assertEquals(220, ZeroOneKnapsack.compute(val, wt, W, val.length), "Expected maximum value is 220 for exact fit."); + } +}