Quick Info

Category: Dynamic Programming
Time Complexity: O(nW)
Space Complexity: O(nW)
Optimal: Yes
In-Place: No

0/1 Knapsack Problem

Description

The 0/1 Knapsack problem is a classic optimization problem where given a set of items, each with a weight and value, we need to determine which items to include in a collection so that the total weight is less than or equal to a given limit and the total value is as large as possible. The term "0/1" indicates that we must either take an item completely (1) or leave it (0).

History

Knapsack Problem Concept

The Knapsack problem was first studied in the early 20th century and has since become one of the most researched problems in combinatorial optimization. Its name comes from the problem faced by someone who is constrained by a fixed-size knapsack and must fill it with the most valuable items. The problem has found applications in resource allocation, cargo loading, cutting stock problems, and even in cryptography. The dynamic programming solution was developed in the 1950s and remains the most practical approach for moderate-sized instances.

How It Works

  1. Initialize DP Table:
    • Create a table of size (n+1) × (W+1)
    • n is number of items, W is capacity
    • Initialize first row and column with zeros
  2. Fill DP Table:
    • For each item i and weight w
    • If item can fit (weight ≤ w), choose maximum of:
    • - Including item: value[i] + dp[i-1][w-weight[i]]
    • - Excluding item: dp[i-1][w]
  3. Trace Solution:
    • Start from bottom-right cell
    • Compare with cell above to determine if item was included
    • Move to previous state based on decision

Visualization

Click Start to begin visualization

Implementation


def knapsack(values, weights, capacity):
    n = len(values)
    dp = [[0 for _ in range(capacity + 1)] for _ in range(n + 1)]
    
    # Fill dp table
    for i in range(1, n + 1):
        for w in range(capacity + 1):
            if weights[i-1] <= w:
                dp[i][w] = max(
                    values[i-1] + dp[i-1][w-weights[i-1]],  # Include item
                    dp[i-1][w]                              # Exclude item
                )
            else:
                dp[i][w] = dp[i-1][w]  # Can't include item
    
    # Find selected items
    selected = []
    i, w = n, capacity
    while i > 0 and w > 0:
        if dp[i][w] != dp[i-1][w]:
            selected.append(i-1)
            w -= weights[i-1]
        i -= 1
    
    return dp[n][capacity], selected[::-1]

# Example usage
if __name__ == "__main__":
    values = [3, 4, 5, 6]
    weights = [2, 3, 4, 5]
    capacity = 10
    
    max_value, selected_items = knapsack(values, weights, capacity)
    print(f"Maximum value: {max_value}")
    print(f"Selected items: {selected_items}")

#include <vector>
#include <iostream>

struct KnapsackResult {
    int maxValue;
    std::vector selectedItems;
};

KnapsackResult knapsack(const std::vector& values, 
                       const std::vector& weights, 
                       int capacity) {
    int n = values.size();
    std::vector> dp(n + 1, 
        std::vector(capacity + 1, 0));
    
    // Fill dp table
    for(int i = 1; i <= n; i++) {
        for(int w = 0; w <= capacity; w++) {
            if(weights[i-1] <= w) {
                dp[i][w] = std::max(
                    values[i-1] + dp[i-1][w-weights[i-1]],
                    dp[i-1][w]
                );
            } else {
                dp[i][w] = dp[i-1][w];
            }
        }
    }
    
    // Find selected items
    std::vector selected;
    int i = n, w = capacity;
    while(i > 0 && w > 0) {
        if(dp[i][w] != dp[i-1][w]) {
            selected.push_back(i-1);
            w -= weights[i-1];
        }
        i--;
    }
    
    // Reverse to get items in original order
    std::reverse(selected.begin(), selected.end());
    
    return {dp[n][capacity], selected};
}

int main() {
    std::vector values = {3, 4, 5, 6};
    std::vector weights = {2, 3, 4, 5};
    int capacity = 10;
    
    auto result = knapsack(values, weights, capacity);
    
    std::cout << "Maximum value: " << result.maxValue << std::endl;
    std::cout << "Selected items: ";
    for(int item : result.selectedItems) {
        std::cout << item << " ";
    }
    std::cout << std::endl;
    
    return 0;
}

using System;
using System.Collections.Generic;

public class KnapsackSolver {
    public class KnapsackResult {
        public int MaxValue { get; set; }
        public List<int> SelectedItems { get; set; }
    }
    
    public static KnapsackResult Solve(int[] values, int[] weights, int capacity) {
        int n = values.Length;
        int[,] dp = new int[n + 1, capacity + 1];
        
        // Fill dp table
        for(int i = 1; i <= n; i++) {
            for(int w = 0; w <= capacity; w++) {
                if(weights[i-1] <= w) {
                    dp[i,w] = Math.Max(
                        values[i-1] + dp[i-1,w-weights[i-1]],
                        dp[i-1,w]
                    );
                } else {
                    dp[i,w] = dp[i-1,w];
                }
            }
        }
        
        // Find selected items
        List<int> selected = new List<int>();
        int currentWeight = capacity;
        for(int i = n; i > 0 && currentWeight > 0; i--) {
            if(dp[i,currentWeight] != dp[i-1,currentWeight]) {
                selected.Add(i-1);
                currentWeight -= weights[i-1];
            }
        }
        
        // Reverse to get items in original order
        selected.Reverse();
        
        return new KnapsackResult {
            MaxValue = dp[n,capacity],
            SelectedItems = selected
        };
    }
    
    public static void Main(string[] args) {
        int[] values = {3, 4, 5, 6};
        int[] weights = {2, 3, 4, 5};
        int capacity = 10;
        
        var result = Solve(values, weights, capacity);
        
        Console.WriteLine($"Maximum value: {result.MaxValue}");
        Console.WriteLine($"Selected items: {string.Join(" ", result.SelectedItems)}");
    }
}

Complexity Analysis

Metric Complexity Notes
Time Complexity O(nW) n items, W capacity
Space Complexity O(nW) DP table size

Notes:

  • n - Number of items
  • W - Knapsack capacity
  • Space can be optimized to O(W) using 1D array
  • Time complexity is pseudo-polynomial
  • NP-hard problem in its decision version

Advantages and Disadvantages

Advantages

  • Finds optimal solution guaranteed
  • Can handle arbitrary values and weights
  • Easy to modify for variations
  • Solution is deterministic
  • Can be optimized for space

Disadvantages

  • Pseudo-polynomial time complexity
  • High memory usage for large capacities
  • Not suitable for fractional items
  • Impractical for very large instances
  • No approximation guarantee if simplified