Definition
Bi Knapsack Dynamic Programming Algorithm
For Bi Knapsack, define
Compute all states for , , . The final entry is the optimal cardinality. The running time is pseudopolynomial in the two capacities.
Recurrence
Budgets are upper bounds, not exact weights
Initialise for all budgets: the empty selection fits every nonnegative pair. This differs from an exact-weight table, in which most base states would be unreachable.
To process item , skipping gives . If and , taking it gives
Both capacities decrease when taking one item. The predecessor lies in layer , not the current layer: the same item cannot be selected twice. Take the larger of the skip value and the take value when the latter is available.
Pseudocode and reconstruction
for every budget s1,s2:
T[0,s1,s2] = 0
for i = 1,...,n:
for s1 = 0,...,S1:
for s2 = 0,...,S2:
T[i,s1,s2] = T[i-1,s1,s2]
if a[i] <= s1 and b[i] <= s2:
T[i,s1,s2] = max(T[i,s1,s2],
1 + T[i-1,s1-a[i],s2-b[i]])
return T[n,S1,S2]To return a subset as well as its value, backtrack from . If the value equals the skip predecessor, skip that item. Otherwise take it, subtract both sizes from the budgets, and move to layer . Equality can be resolved by skipping. Continue until layer zero.
Correctness
Induction on the number of available items
Base layer
With no available items, the empty set is the only selection and has cardinality zero. Every base entry is correct.
Upper bound every feasible selection
Assume layer is correct. A feasible selection either omits item , giving value at most the skip predecessor, or contains it. In the latter case the remaining items fit the two reduced budgets, giving value at most one plus the take predecessor.
Attain each candidate
An optimal skip predecessor remains feasible. An optimal take predecessor together with item fits both budgets whenever the take condition holds. Therefore the maximum of the available candidates is both an upper bound and attainable. This establishes the invariant, and hence the final optimum and backtracking procedure.
State count and encoding length
The table contains exactly cells, with constant many arithmetic operations per cell. Values lie in and use bits. Two rolling layers suffice for the value alone; storing all layers permits the direct reconstruction above.
The capacities are numerical bounds, not their bit lengths. For example, a capacity needs only binary digits, but an axis indexed by has positions. With two such capacities, the table has positions per layer. This shows why the stated implementation need not be polynomial in binary input length.
Under unary encoding, both capacities and the number of items are bounded by the input length, so the state count is polynomial. This pseudopolynomial algorithm does not imply an FPTAS: Bi Knapsack has no FPTAS unless P equals NP.