def knapsack_01_dp(values, weights, capacity):
"""
0/1 Knapsack - Dynamic Programming solution
Args:
values: List of item values [v1, v2, ..., vn]
weights: List of item weights [w1, w2, ..., wn]
capacity: Maximum weight capacity (W)
Returns:
tuple: (max_value, selected_items)
- max_value: Maximum achievable value
- selected_items: List of indices of selected items
Time Complexity: O(n * W)
Space Complexity: O(n * W)
"""
n = len(values)
# Create DP table: dp[i][w] = max value using first i items with capacity w
dp = [[0] * (capacity + 1) for _ in range(n + 1)]
# Build table bottom-up
for i in range(1, n + 1):
for w in range(capacity + 1):
if weights[i-1] <= w:
# Option 1: Take the item
take_value = dp[i-1][w - weights[i-1]] + values[i-1]
# Option 2: Skip the item
skip_value = dp[i-1][w]
dp[i][w] = max(take_value, skip_value)
else:
# Can't take the item (too heavy)
dp[i][w] = dp[i-1][w]
# Reconstruct selected items (backtracking)
selected = []
w = capacity
for i in range(n, 0, -1):
if dp[i][w] != dp[i-1][w]: # Item was taken
selected.append(i-1)
w -= weights[i-1]
return dp[n][capacity], selected[::-1]
def knapsack_01_dp_optimized(values, weights, capacity):
"""
0/1 Knapsack - Space-optimized DP (1D array)
Time Complexity: O(n * W)
Space Complexity: O(W)
"""
n = len(values)
dp = [0] * (capacity + 1)
for i in range(n):
# Iterate backwards to avoid overwriting
for w in range(capacity, weights[i] - 1, -1):
dp[w] = max(dp[w], dp[w - weights[i]] + values[i])
return dp[capacity]
def knapsack_01_brute_force(values, weights, capacity):
"""
0/1 Knapsack - Brute Force (for comparison)
Time Complexity: O(2^n)
Space Complexity: O(n)
"""
n = len(values)
max_value = 0
best_combo = []
# Try all 2^n combinations
for i in range(1 << n):
current_weight = 0
current_value = 0
selected = []
for j in range(n):
if i & (1 << j): # Item j is selected
current_weight += weights[j]
current_value += values[j]
selected.append(j)
if current_weight <= capacity and current_value > max_value:
max_value = current_value
best_combo = selected
return max_value, best_combo
def print_solution(values, weights, capacity, max_value, selected_items):
"""Pretty print the solution"""
print(f"\n{'='*50}")
print("0/1 KNAPSACK SOLUTION")
print(f"{'='*50}")
print(f"Items: {len(values)}")
print(f"Capacity: {capacity}")
print(f"Max Value: {max_value}")
print(f"Selected Items: {selected_items}")
total_weight = sum(weights[i] for i in selected_items)
total_value = sum(values[i] for i in selected_items)
print(f"Total Weight: {total_weight}")
print(f"Total Value: {total_value}")
print("\nItem Details:")
for i in selected_items:
print(f" Item {i}: value={values[i]}, weight={weights[i]}")
# ============= EXAMPLES =============
def run_examples():
"""Run test cases"""
# Example 1: Classic problem
print("\n" + "="*60)
print("EXAMPLE 1: Classic 0/1 Knapsack")
print("="*60)
values = [60, 100, 120]
weights = [10, 20, 30]
capacity = 50
max_val, selected = knapsack_01_dp(values, weights, capacity)
print_solution(values, weights, capacity, max_val, selected)
# Compare with brute force
max_val_bf, selected_bf = knapsack_01_brute_force(values, weights, capacity)
print(f"\nBrute Force Result: {max_val_bf}")
print(f"Brute Force Selected: {selected_bf}")
# Example 2: Larger problem
print("\n" + "="*60)
print("EXAMPLE 2: Larger Knapsack")
print("="*60)
values = [20, 5, 10, 40, 15, 25]
weights = [1, 2, 3, 8, 7, 4]
capacity = 10
max_val, selected = knapsack_01_dp(values, weights, capacity)
print_solution(values, weights, capacity, max_val, selected)
# Example 3: Real-world scenario
print("\n" + "="*60)
print("EXAMPLE 3: Backpack Problem")
print("="*60)
items = [
("Laptop", 500, 2),
("Camera", 300, 1),
("Books", 150, 3),
("Clothes", 200, 4),
("Food", 100, 2),
("Tent", 400, 5),
("Sleeping Bag", 250, 3),
("First Aid", 180, 1),
]
values = [item[1] for item in items]
weights = [item[2] for item in items]
capacity = 10 # kg
max_val, selected = knapsack_01_dp(values, weights, capacity)
print(f"Backpack capacity: {capacity} kg")
print(f"Maximum value: ${max_val}")
print("\nSelected items:")
total_weight = 0
for i in selected:
name, value, weight = items[i]
total_weight += weight
print(f" - {name}: ${value} ({weight} kg)")
print(f"Total weight: {total_weight} kg")
if __name__ == "__main__":
run_examples()
ZGVmIGtuYXBzYWNrXzAxX2RwKHZhbHVlcywgd2VpZ2h0cywgY2FwYWNpdHkpOgogICAgIiIiCiAgICAwLzEgS25hcHNhY2sgLSBEeW5hbWljIFByb2dyYW1taW5nIHNvbHV0aW9uCiAgICAKICAgIEFyZ3M6CiAgICAgICAgdmFsdWVzOiBMaXN0IG9mIGl0ZW0gdmFsdWVzIFt2MSwgdjIsIC4uLiwgdm5dCiAgICAgICAgd2VpZ2h0czogTGlzdCBvZiBpdGVtIHdlaWdodHMgW3cxLCB3MiwgLi4uLCB3bl0KICAgICAgICBjYXBhY2l0eTogTWF4aW11bSB3ZWlnaHQgY2FwYWNpdHkgKFcpCiAgICAKICAgIFJldHVybnM6CiAgICAgICAgdHVwbGU6IChtYXhfdmFsdWUsIHNlbGVjdGVkX2l0ZW1zKQogICAgICAgICAgICAgICAtIG1heF92YWx1ZTogTWF4aW11bSBhY2hpZXZhYmxlIHZhbHVlCiAgICAgICAgICAgICAgIC0gc2VsZWN0ZWRfaXRlbXM6IExpc3Qgb2YgaW5kaWNlcyBvZiBzZWxlY3RlZCBpdGVtcwogICAgCiAgICBUaW1lIENvbXBsZXhpdHk6IE8obiAqIFcpCiAgICBTcGFjZSBDb21wbGV4aXR5OiBPKG4gKiBXKQogICAgIiIiCiAgICBuID0gbGVuKHZhbHVlcykKICAgIAogICAgIyBDcmVhdGUgRFAgdGFibGU6IGRwW2ldW3ddID0gbWF4IHZhbHVlIHVzaW5nIGZpcnN0IGkgaXRlbXMgd2l0aCBjYXBhY2l0eSB3CiAgICBkcCA9IFtbMF0gKiAoY2FwYWNpdHkgKyAxKSBmb3IgXyBpbiByYW5nZShuICsgMSldCiAgICAKICAgICMgQnVpbGQgdGFibGUgYm90dG9tLXVwCiAgICBmb3IgaSBpbiByYW5nZSgxLCBuICsgMSk6CiAgICAgICAgZm9yIHcgaW4gcmFuZ2UoY2FwYWNpdHkgKyAxKToKICAgICAgICAgICAgaWYgd2VpZ2h0c1tpLTFdIDw9IHc6CiAgICAgICAgICAgICAgICAjIE9wdGlvbiAxOiBUYWtlIHRoZSBpdGVtCiAgICAgICAgICAgICAgICB0YWtlX3ZhbHVlID0gZHBbaS0xXVt3IC0gd2VpZ2h0c1tpLTFdXSArIHZhbHVlc1tpLTFdCiAgICAgICAgICAgICAgICAjIE9wdGlvbiAyOiBTa2lwIHRoZSBpdGVtCiAgICAgICAgICAgICAgICBza2lwX3ZhbHVlID0gZHBbaS0xXVt3XQogICAgICAgICAgICAgICAgZHBbaV1bd10gPSBtYXgodGFrZV92YWx1ZSwgc2tpcF92YWx1ZSkKICAgICAgICAgICAgZWxzZToKICAgICAgICAgICAgICAgICMgQ2FuJ3QgdGFrZSB0aGUgaXRlbSAodG9vIGhlYXZ5KQogICAgICAgICAgICAgICAgZHBbaV1bd10gPSBkcFtpLTFdW3ddCiAgICAKICAgICMgUmVjb25zdHJ1Y3Qgc2VsZWN0ZWQgaXRlbXMgKGJhY2t0cmFja2luZykKICAgIHNlbGVjdGVkID0gW10KICAgIHcgPSBjYXBhY2l0eQogICAgZm9yIGkgaW4gcmFuZ2UobiwgMCwgLTEpOgogICAgICAgIGlmIGRwW2ldW3ddICE9IGRwW2ktMV1bd106ICAjIEl0ZW0gd2FzIHRha2VuCiAgICAgICAgICAgIHNlbGVjdGVkLmFwcGVuZChpLTEpCiAgICAgICAgICAgIHcgLT0gd2VpZ2h0c1tpLTFdCiAgICAKICAgIHJldHVybiBkcFtuXVtjYXBhY2l0eV0sIHNlbGVjdGVkWzo6LTFdCgoKZGVmIGtuYXBzYWNrXzAxX2RwX29wdGltaXplZCh2YWx1ZXMsIHdlaWdodHMsIGNhcGFjaXR5KToKICAgICIiIgogICAgMC8xIEtuYXBzYWNrIC0gU3BhY2Utb3B0aW1pemVkIERQICgxRCBhcnJheSkKICAgIAogICAgVGltZSBDb21wbGV4aXR5OiBPKG4gKiBXKQogICAgU3BhY2UgQ29tcGxleGl0eTogTyhXKQogICAgIiIiCiAgICBuID0gbGVuKHZhbHVlcykKICAgIGRwID0gWzBdICogKGNhcGFjaXR5ICsgMSkKICAgIAogICAgZm9yIGkgaW4gcmFuZ2Uobik6CiAgICAgICAgIyBJdGVyYXRlIGJhY2t3YXJkcyB0byBhdm9pZCBvdmVyd3JpdGluZwogICAgICAgIGZvciB3IGluIHJhbmdlKGNhcGFjaXR5LCB3ZWlnaHRzW2ldIC0gMSwgLTEpOgogICAgICAgICAgICBkcFt3XSA9IG1heChkcFt3XSwgZHBbdyAtIHdlaWdodHNbaV1dICsgdmFsdWVzW2ldKQogICAgCiAgICByZXR1cm4gZHBbY2FwYWNpdHldCgoKZGVmIGtuYXBzYWNrXzAxX2JydXRlX2ZvcmNlKHZhbHVlcywgd2VpZ2h0cywgY2FwYWNpdHkpOgogICAgIiIiCiAgICAwLzEgS25hcHNhY2sgLSBCcnV0ZSBGb3JjZSAoZm9yIGNvbXBhcmlzb24pCiAgICAKICAgIFRpbWUgQ29tcGxleGl0eTogTygyXm4pCiAgICBTcGFjZSBDb21wbGV4aXR5OiBPKG4pCiAgICAiIiIKICAgIG4gPSBsZW4odmFsdWVzKQogICAgbWF4X3ZhbHVlID0gMAogICAgYmVzdF9jb21ibyA9IFtdCiAgICAKICAgICMgVHJ5IGFsbCAyXm4gY29tYmluYXRpb25zCiAgICBmb3IgaSBpbiByYW5nZSgxIDw8IG4pOgogICAgICAgIGN1cnJlbnRfd2VpZ2h0ID0gMAogICAgICAgIGN1cnJlbnRfdmFsdWUgPSAwCiAgICAgICAgc2VsZWN0ZWQgPSBbXQogICAgICAgIAogICAgICAgIGZvciBqIGluIHJhbmdlKG4pOgogICAgICAgICAgICBpZiBpICYgKDEgPDwgaik6ICAjIEl0ZW0gaiBpcyBzZWxlY3RlZAogICAgICAgICAgICAgICAgY3VycmVudF93ZWlnaHQgKz0gd2VpZ2h0c1tqXQogICAgICAgICAgICAgICAgY3VycmVudF92YWx1ZSArPSB2YWx1ZXNbal0KICAgICAgICAgICAgICAgIHNlbGVjdGVkLmFwcGVuZChqKQogICAgICAgIAogICAgICAgIGlmIGN1cnJlbnRfd2VpZ2h0IDw9IGNhcGFjaXR5IGFuZCBjdXJyZW50X3ZhbHVlID4gbWF4X3ZhbHVlOgogICAgICAgICAgICBtYXhfdmFsdWUgPSBjdXJyZW50X3ZhbHVlCiAgICAgICAgICAgIGJlc3RfY29tYm8gPSBzZWxlY3RlZAogICAgCiAgICByZXR1cm4gbWF4X3ZhbHVlLCBiZXN0X2NvbWJvCgoKZGVmIHByaW50X3NvbHV0aW9uKHZhbHVlcywgd2VpZ2h0cywgY2FwYWNpdHksIG1heF92YWx1ZSwgc2VsZWN0ZWRfaXRlbXMpOgogICAgIiIiUHJldHR5IHByaW50IHRoZSBzb2x1dGlvbiIiIgogICAgcHJpbnQoZiJcbnsnPScqNTB9IikKICAgIHByaW50KCIwLzEgS05BUFNBQ0sgU09MVVRJT04iKQogICAgcHJpbnQoZiJ7Jz0nKjUwfSIpCiAgICBwcmludChmIkl0ZW1zOiB7bGVuKHZhbHVlcyl9IikKICAgIHByaW50KGYiQ2FwYWNpdHk6IHtjYXBhY2l0eX0iKQogICAgcHJpbnQoZiJNYXggVmFsdWU6IHttYXhfdmFsdWV9IikKICAgIHByaW50KGYiU2VsZWN0ZWQgSXRlbXM6IHtzZWxlY3RlZF9pdGVtc30iKQogICAgCiAgICB0b3RhbF93ZWlnaHQgPSBzdW0od2VpZ2h0c1tpXSBmb3IgaSBpbiBzZWxlY3RlZF9pdGVtcykKICAgIHRvdGFsX3ZhbHVlID0gc3VtKHZhbHVlc1tpXSBmb3IgaSBpbiBzZWxlY3RlZF9pdGVtcykKICAgIAogICAgcHJpbnQoZiJUb3RhbCBXZWlnaHQ6IHt0b3RhbF93ZWlnaHR9IikKICAgIHByaW50KGYiVG90YWwgVmFsdWU6IHt0b3RhbF92YWx1ZX0iKQogICAgcHJpbnQoIlxuSXRlbSBEZXRhaWxzOiIpCiAgICBmb3IgaSBpbiBzZWxlY3RlZF9pdGVtczoKICAgICAgICBwcmludChmIiAgSXRlbSB7aX06IHZhbHVlPXt2YWx1ZXNbaV19LCB3ZWlnaHQ9e3dlaWdodHNbaV19IikKCgojID09PT09PT09PT09PT0gRVhBTVBMRVMgPT09PT09PT09PT09PQoKZGVmIHJ1bl9leGFtcGxlcygpOgogICAgIiIiUnVuIHRlc3QgY2FzZXMiIiIKICAgIAogICAgIyBFeGFtcGxlIDE6IENsYXNzaWMgcHJvYmxlbQogICAgcHJpbnQoIlxuIiArICI9Iio2MCkKICAgIHByaW50KCJFWEFNUExFIDE6IENsYXNzaWMgMC8xIEtuYXBzYWNrIikKICAgIHByaW50KCI9Iio2MCkKICAgIAogICAgdmFsdWVzID0gWzYwLCAxMDAsIDEyMF0KICAgIHdlaWdodHMgPSBbMTAsIDIwLCAzMF0KICAgIGNhcGFjaXR5ID0gNTAKICAgIAogICAgbWF4X3ZhbCwgc2VsZWN0ZWQgPSBrbmFwc2Fja18wMV9kcCh2YWx1ZXMsIHdlaWdodHMsIGNhcGFjaXR5KQogICAgcHJpbnRfc29sdXRpb24odmFsdWVzLCB3ZWlnaHRzLCBjYXBhY2l0eSwgbWF4X3ZhbCwgc2VsZWN0ZWQpCiAgICAKICAgICMgQ29tcGFyZSB3aXRoIGJydXRlIGZvcmNlCiAgICBtYXhfdmFsX2JmLCBzZWxlY3RlZF9iZiA9IGtuYXBzYWNrXzAxX2JydXRlX2ZvcmNlKHZhbHVlcywgd2VpZ2h0cywgY2FwYWNpdHkpCiAgICBwcmludChmIlxuQnJ1dGUgRm9yY2UgUmVzdWx0OiB7bWF4X3ZhbF9iZn0iKQogICAgcHJpbnQoZiJCcnV0ZSBGb3JjZSBTZWxlY3RlZDoge3NlbGVjdGVkX2JmfSIpCiAgICAKICAgICMgRXhhbXBsZSAyOiBMYXJnZXIgcHJvYmxlbQogICAgcHJpbnQoIlxuIiArICI9Iio2MCkKICAgIHByaW50KCJFWEFNUExFIDI6IExhcmdlciBLbmFwc2FjayIpCiAgICBwcmludCgiPSIqNjApCiAgICAKICAgIHZhbHVlcyA9IFsyMCwgNSwgMTAsIDQwLCAxNSwgMjVdCiAgICB3ZWlnaHRzID0gWzEsIDIsIDMsIDgsIDcsIDRdCiAgICBjYXBhY2l0eSA9IDEwCiAgICAKICAgIG1heF92YWwsIHNlbGVjdGVkID0ga25hcHNhY2tfMDFfZHAodmFsdWVzLCB3ZWlnaHRzLCBjYXBhY2l0eSkKICAgIHByaW50X3NvbHV0aW9uKHZhbHVlcywgd2VpZ2h0cywgY2FwYWNpdHksIG1heF92YWwsIHNlbGVjdGVkKQogICAgCiAgICAjIEV4YW1wbGUgMzogUmVhbC13b3JsZCBzY2VuYXJpbwogICAgcHJpbnQoIlxuIiArICI9Iio2MCkKICAgIHByaW50KCJFWEFNUExFIDM6IEJhY2twYWNrIFByb2JsZW0iKQogICAgcHJpbnQoIj0iKjYwKQogICAgCiAgICBpdGVtcyA9IFsKICAgICAgICAoIkxhcHRvcCIsIDUwMCwgMiksCiAgICAgICAgKCJDYW1lcmEiLCAzMDAsIDEpLAogICAgICAgICgiQm9va3MiLCAxNTAsIDMpLAogICAgICAgICgiQ2xvdGhlcyIsIDIwMCwgNCksCiAgICAgICAgKCJGb29kIiwgMTAwLCAyKSwKICAgICAgICAoIlRlbnQiLCA0MDAsIDUpLAogICAgICAgICgiU2xlZXBpbmcgQmFnIiwgMjUwLCAzKSwKICAgICAgICAoIkZpcnN0IEFpZCIsIDE4MCwgMSksCiAgICBdCiAgICAKICAgIHZhbHVlcyA9IFtpdGVtWzFdIGZvciBpdGVtIGluIGl0ZW1zXQogICAgd2VpZ2h0cyA9IFtpdGVtWzJdIGZvciBpdGVtIGluIGl0ZW1zXQogICAgY2FwYWNpdHkgPSAxMCAgIyBrZwogICAgCiAgICBtYXhfdmFsLCBzZWxlY3RlZCA9IGtuYXBzYWNrXzAxX2RwKHZhbHVlcywgd2VpZ2h0cywgY2FwYWNpdHkpCiAgICAKICAgIHByaW50KGYiQmFja3BhY2sgY2FwYWNpdHk6IHtjYXBhY2l0eX0ga2ciKQogICAgcHJpbnQoZiJNYXhpbXVtIHZhbHVlOiAke21heF92YWx9IikKICAgIHByaW50KCJcblNlbGVjdGVkIGl0ZW1zOiIpCiAgICB0b3RhbF93ZWlnaHQgPSAwCiAgICBmb3IgaSBpbiBzZWxlY3RlZDoKICAgICAgICBuYW1lLCB2YWx1ZSwgd2VpZ2h0ID0gaXRlbXNbaV0KICAgICAgICB0b3RhbF93ZWlnaHQgKz0gd2VpZ2h0CiAgICAgICAgcHJpbnQoZiIgIC0ge25hbWV9OiAke3ZhbHVlfSAoe3dlaWdodH0ga2cpIikKICAgIHByaW50KGYiVG90YWwgd2VpZ2h0OiB7dG90YWxfd2VpZ2h0fSBrZyIpCgoKaWYgX19uYW1lX18gPT0gIl9fbWFpbl9fIjoKICAgIHJ1bl9leGFtcGxlcygp