Recursion and Dynamic Programming
0/1 Knapsack (Small)
Fill a small 0/1 knapsack table where each row decides whether one more item is available.
Algorithm
@steps
- Create a table with one extra row for using zero items.
- Process the four items in fixed order.
- For each capacity, inherit when the item is too heavy.
- Otherwise compare
skipandtakefrom the previous row. - Print the best value and the full deterministic table. @end @complexity
- Time: O(item_count * capacity)
- Space: O(item_count * capacity) @end
state transition
`dp[i][w]` compares skipping item `i` with taking it and reading the remaining capacity from the previous row.
Rust DSA Implementation
basic.rs
fn row_string(row: &[i32]) -> String {
format!("[{}]", row.iter().map(|v| v.to_string()).collect::<Vec<_>>().join(", "))
}
fn table_string(table: &[Vec<i32>]) -> String {
format!("[{}]", table.iter().map(|r| row_string(r)).collect::<Vec<_>>().join(", "))
}
fn main() {
let weights = [2usize, 3, 4, 5];
let values = [3, 4, 5, 6];
let capacity = 5usize;
let mut dp = vec![vec![0; capacity + 1]; weights.len() + 1];
for item in 1..=weights.len() {
let weight = weights[item - 1];
let value = values[item - 1];
for cap in 0..=capacity {
if weight > cap {
dp[item][cap] = dp[item - 1][cap];
} else {
let skip = dp[item - 1][cap];
let take = value + dp[item - 1][cap - weight];
dp[item][cap] = skip.max(take);
}
}
}
println!("{}", dp[weights.len()][capacity]);
println!("{}", table_string(&dp));
}
@end @output 7 [[0, 0, 0, 0, 0, 0], [0, 0, 3, 3, 3, 3], [0, 0, 3, 4, 4, 7], [0, 0, 3, 4, 5, 7], [0, 0, 3, 4, 5, 7]] @end