Knapsack (Recovering Items)

Problem:
Given a knapsack with capacity n and m items, where each item has a value and weight, determine the maximum value that can be placed in the knapsack.

In addition to the maximum value, return which items were selected.

This is the classic Knapsack dynamic programming problem with backtracking.


💡 Approach

We define a DP table:

t[i][j] = maximum value using the first i items with capacity j

Each item gives us two choices.

1️⃣ Skip the item

Do not include item i.

t[i-1][j]

2️⃣ Take the item

If the weight allows, include item i.

t[i-1][j - weight] + value

So the recurrence is:

t[i][j] = max(t[i-1][j], t[i-1][j-weight] + value)

Why this works

At every item, we choose between:

The DP table builds optimal solutions for all prefixes of items and capacities.


🔍 Recovering the Selected Items

After filling the table, we backtrack from t[m][n]:

This lets us reconstruct the actual set of chosen items.



import sys

for line in sys.stdin:
    line = line.strip()
    if not line:
        continue

    # capacity n, number of items m
    n, m = map(int, line.split())

    # DP table
    t = [[0] * (n + 1) for _ in range(m + 1)]

    items = []

    # build DP table
    for i in range(1, m + 1):
        value, weight = map(int, sys.stdin.readline().split())
        items.append((value, weight))

        for j in range(1, n + 1):
            if weight <= j:
                t[i][j] = max(t[i-1][j], t[i-1][j-weight] + value)
            else:
                t[i][j] = t[i-1][j]

    # backtrack to find selected items
    selected_items = []
    j = n

    for i in range(m, 0, -1):
        value, weight = items[i-1]

        if j >= weight and t[i][j] == t[i-1][j-weight] + value:
            selected_items.append(i-1)
            j -= weight

    selected_items.reverse()

    # output
    print(len(selected_items))
    print(" ".join(map(str, selected_items)))