Implementing 0-1 Knapsack in Java

The 0-1 Knapsack problem is a fundamental problem in combinatorial optimization: given a set of items, each with a weight and a profit, find the subset of items that maximises total profit without exceeding a weight capacity. The “0-1” constraint means you must either take an item entirely or leave it — no fractions allowed. Unlike the Fractional Knapsack, this requires dynamic programming to find the optimal solution, since greedy selection does not guarantee optimality.

0-1 Knapsack using Dynamic Programming in Java

import java.io.*;

class Knapsack01 {

    /**
     * Builds the DP table and computes the maximum achievable profit.
     *
     * @param weights    weight of each item (1-indexed)
     * @param profits    profit of each item (1-indexed)
     * @param itemCount  number of items
     * @param maxCapacity maximum knapsack weight capacity
     */
    void solve(int[] weights, int[] profits, int itemCount, int maxCapacity) {
        // dpTable[i][j] = max profit using first i items with capacity j
        int[][] dpTable = new int[itemCount + 1][maxCapacity + 1];

        // Base cases: 0 items or 0 capacity yields 0 profit
        for (int capacity = 0; capacity <= maxCapacity; capacity++)
            dpTable[0][capacity] = 0;
        for (int i = 0; i <= itemCount; i++)
            dpTable[i][0] = 0;

        // Fill the DP table
        for (int i = 1; i <= itemCount; i++) {
            for (int j = 0; j <= maxCapacity; j++) {
                if (weights[i] <= j) {
                    // Item i can fit: choose the better option
                    // Option A: include item i  -- profits[i] + best profit for remaining capacity
                    // Option B: exclude item i  -- same as best profit without item i
                    int profitWithItem    = profits[i] + dpTable[i - 1][j - weights[i]];
                    int profitWithoutItem = dpTable[i - 1][j];
                    dpTable[i][j] = Math.max(profitWithItem, profitWithoutItem);
                } else {
                    // Item i does not fit: carry forward the profit without it
                    dpTable[i][j] = dpTable[i - 1][j];
                }
            }
        }

        // Trace back through the DP table to find which items were selected
        findSelectedItems(dpTable, itemCount, maxCapacity, weights, profits);
    }

    /**
     * Traces back through dpTable to determine which items were included
     * in the optimal solution.
     */
    void findSelectedItems(int[][] dpTable, int itemCount, int maxCapacity,
                           int[] weights, int[] profits) {
        int[] selectedItems = new int[itemCount + 1];  // 1 = included, 0 = excluded
        int   currentItem   = itemCount;
        int   currentCap    = maxCapacity;
        int   totalProfit   = 0;

        // Walk backwards: if dpTable[i][cap] != dpTable[i-1][cap], item i was included
        while (currentItem > 0 && currentCap > 0) {
            if (dpTable[currentItem][currentCap] != dpTable[currentItem - 1][currentCap]) {
                selectedItems[currentItem] = 1;           // item was taken
                totalProfit               += profits[currentItem];
                currentCap                -= weights[currentItem];  // reduce capacity
            }
            currentItem--;
        }

        // Display results
        System.out.println("Selected items (1 = included, 0 = excluded):");
        for (int i = 1; i <= itemCount; i++) {
            System.out.println("Item " + i + ": " + selectedItems[i]);
        }
        System.out.println("Maximum Profit: " + totalProfit);
    }
}

class Knapsack01Main {
    public static void main(String[] args) throws IOException {
        Knapsack01 knapsack = new Knapsack01();
        BufferedReader reader = new BufferedReader(new InputStreamReader(System.in));

        System.out.println("How many items?");
        int itemCount = Integer.parseInt(reader.readLine());

        System.out.println("Enter the knapsack capacity:");
        int maxCapacity = Integer.parseInt(reader.readLine());

        int[] profits = new int[itemCount + 1];  // 1-indexed
        int[] weights = new int[itemCount + 1];  // 1-indexed

        System.out.println("Enter profit and weight for each item:");
        for (int i = 1; i <= itemCount; i++) {
            System.out.print("Profit of item " + i + ": ");
            profits[i] = Integer.parseInt(reader.readLine());
            System.out.print("Weight of item " + i + ": ");
            weights[i] = Integer.parseInt(reader.readLine());
            System.out.println();
        }

        knapsack.solve(weights, profits, itemCount, maxCapacity);
    }
}

How the Code Works

  1. DP table setup: dpTable[i][j] stores the maximum profit achievable using the first i items with a knapsack of capacity j. It is initialised to 0 for the base cases (0 items or 0 capacity).
  2. Recurrence relation: for each item i and capacity j:
    • If weights[i] > j: item cannot fit → dpTable[i][j] = dpTable[i-1][j]
    • Otherwise: take the maximum of including or excluding the item.
  3. Traceback: findSelectedItems() walks the DP table backwards. If dpTable[i][cap] != dpTable[i-1][cap], item i contributed to the optimal solution and is marked as selected.
  4. Result: the final maximum profit is read from dpTable[itemCount][maxCapacity], and the traceback reveals exactly which items were included.

Sample Output

How many items?
4
Enter the knapsack capacity:
15
Enter profit and weight for each item:
Profit of item 1: 5
Weight of item 1: 6

Profit of item 2: 8
Weight of item 2: 9

Profit of item 3: 5
Weight of item 3: 6

Profit of item 4: 4
Weight of item 4: 7

Selected items (1 = included, 0 = excluded):
Item 1: 1
Item 2: 1
Item 3: 0
Item 4: 0
Maximum Profit: 13

Output Explanation

  1. With capacity 15, items 1 (weight 6) and 2 (weight 9) together weigh 15 and yield profit 5+8 = 13.
  2. No other combination fits within 15 and yields more than 13: e.g., items 1+3 weigh 12 (profit 10), items 2+4 weigh 16 (exceeds capacity).
  3. The traceback correctly identifies items 1 and 2 as included (value 1) and items 3 and 4 as excluded (value 0).

See Also

Conclusion

The 0-1 Knapsack problem is a foundational dynamic programming example that appears frequently in coding interviews and competitive programming. The key insight is that the optimal solution for n items and capacity C can be built from solutions to smaller sub-problems — a hallmark of DP. The traceback step is just as important as the table-filling step, as it reveals which items were actually selected, not just the maximum profit.

Leave a Reply

This site uses Akismet to reduce spam. Learn how your comment data is processed.