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
- DP table setup:
dpTable[i][j]stores the maximum profit achievable using the firstiitems with a knapsack of capacityj. It is initialised to 0 for the base cases (0 items or 0 capacity). - Recurrence relation: for each item
iand capacityj:- If
weights[i] > j: item cannot fit →dpTable[i][j] = dpTable[i-1][j] - Otherwise: take the maximum of including or excluding the item.
- If
- Traceback:
findSelectedItems()walks the DP table backwards. IfdpTable[i][cap] != dpTable[i-1][cap], itemicontributed to the optimal solution and is marked as selected. - 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
- With capacity 15, items 1 (weight 6) and 2 (weight 9) together weigh 15 and yield profit 5+8 = 13.
- 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).
- The traceback correctly identifies items 1 and 2 as included (value 1) and items 3 and 4 as excluded (value 0).
See Also
- Implementing Greedy (Fractional) Knapsack in Java
- Java Program for Longest Common Subsequence (LCS)
- Implementing Merge Sort Algorithm in Java
- N-Queen Problem in Java
- Minimum Spanning Tree using Prim’s Algorithm in Java
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.