Dynamic Programming Solution for the Knapsack Problem
Description
The knapsack problem is a classic combinatorial optimization problem, commonly encountered in interviews and practical applications. The problem is described as: Given a set of items, each with a weight and a value, and a knapsack with a capacity C. The goal is to select some items to put into the knapsack such that the total weight does not exceed C, and the total value is maximized. The knapsack problem is divided into the 0-1 knapsack (each item can be selected at most once) and the unbounded knapsack (each item can be selected unlimited times). Here, we focus on the dynamic programming solution for the 0-1 knapsack.
Solution Process
Dynamic programming avoids redundant calculations by breaking down the problem into subproblems. For the 0-1 knapsack, the core idea is to consider items and capacities one by one, constructing a two-dimensional DP table.
-
Define State
- Let
dp[i][j]represent the maximum value that can be obtained by considering the firstiitems (items numbered from 1 to i) with a knapsack capacity ofj. - Here,
iranges from 0 to n (n is the total number of items), andjranges from 0 to C (C is the total knapsack capacity).
- Let
-
Initialize Base Cases
- When the number of items is 0 (i=0), regardless of the capacity, the maximum value is 0:
dp[0][j] = 0(j from 0 to C). - When the knapsack capacity is 0 (j=0), regardless of the number of items, the maximum value is 0:
dp[i][0] = 0(i from 0 to n).
- When the number of items is 0 (i=0), regardless of the capacity, the maximum value is 0:
-
State Transition Equation
For each item i and capacity j, there are two cases:- Do not select the i-th item: The maximum value equals the result of the first i-1 items with capacity j, i.e.,
dp[i][j] = dp[i-1][j]. - Select the i-th item (provided the current capacity j ≥ the weight w_i of item i): The maximum value is the value v_i of item i plus the result of the first i-1 items with the remaining capacity
j - w_i, i.e.,dp[i][j] = v_i + dp[i-1][j - w_i]. - Finally, take the maximum of the two cases:
dp[i][j] = max(dp[i-1][j], v_i + dp[i-1][j - w_i])(if j ≥ w_i, otherwise, only the first case applies).
- Do not select the i-th item: The maximum value equals the result of the first i-1 items with capacity j, i.e.,
-
Table Filling Order
- Outer loop iterates over items i from 1 to n, inner loop iterates over capacity j from 1 to C. Ensure that when computing
dp[i][j],dp[i-1][j]anddp[i-1][j - w_i]have already been computed.
- Outer loop iterates over items i from 1 to n, inner loop iterates over capacity j from 1 to C. Ensure that when computing
-
Obtain Final Result
- The maximum value is stored in
dp[n][C]. If it's necessary to know which specific items were selected, backtrack through the DP table: start fromdp[n][C], ifdp[i][j] != dp[i-1][j], it means item i was selected, then jump todp[i-1][j - w_i]and continue backtracking.
- The maximum value is stored in
Example
Assume item list: weights w = [2, 3, 4, 5], values v = [3, 4, 5, 6], capacity C=8.
- Build the table: rows i from 0 to 4 (4 items), columns j from 0 to 8.
- After filling the table,
dp[4][8] = 10(select items 2 and 4, weight 3+5=8, value 4+6=10).
Optimization
- Space optimization: Since
dp[i]depends only ondp[i-1], a one-dimensional arraydp[j]can be used instead, with the inner loop j traversing from C to w_i in reverse order to avoid overwriting the previous state.