Skip to content

Commit 5b7856a

Browse files
authored
Added 0-1 Knapsack (TheAlgorithms#176)
* Added 0-1 Knapsack * Edit 0-1 Knapsack problem * Edited 0-1 Knapsack problem * Corrected all notes 0-1 Knapsack problem * Updated README (0-1 Knapsack)
1 parent fb88840 commit 5b7856a

File tree

4 files changed

+153
-2
lines changed

4 files changed

+153
-2
lines changed

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,3 +5,4 @@
55
/target
66
**/*.rs.bk
77
Cargo.lock
8+
/.idea/

README.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -24,9 +24,9 @@ These are for demonstration purposes only.
2424
- BFS _(Not implemented yet)_
2525
- DFS _(Not implemented yet)_
2626

27-
## [Dynamic Programming](./src/general)
27+
## [Dynamic Programming](./src/dynamic_programming)
2828

29-
- 0-1 Knapsack _(Not implemented yet)_
29+
- [0-1 Knapsack](./src/dynamic_programming/knapsack.rs)
3030
- [Edit Distance](./src/dynamic_programming/edit_distance.rs)
3131
- [Longest common subsequence](./src/dynamic_programming/longest_common_subsequence.rs)
3232
- Longest increasing subsequence _(Not implemented yet)_

src/dynamic_programming/knapsack.rs

Lines changed: 148 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,148 @@
1+
//! Solves the knapsack problem
2+
use std::cmp::max;
3+
4+
/// knapsack_table(w, weights, values) returns the knapsack table (`n`, `m`) with maximum values, where `n` is number of items
5+
///
6+
/// Arguments:
7+
/// * `w` - knapsack capacity
8+
/// * `weights` - set of weights for each item
9+
/// * `values` - set of values for each item
10+
fn knapsack_table(w: &usize, weights: &[usize], values: &[usize]) -> Vec<Vec<usize>> {
11+
// Initialize `n` - number of items
12+
let n: usize = weights.len();
13+
// Initialize `m`
14+
// m[i, w] - the maximum value that can be attained with weight less that or equal to `w` using items up to `i`
15+
let mut m: Vec<Vec<usize>> = vec![vec![0; w + 1]; n + 1];
16+
17+
for i in 0..=n {
18+
for j in 0..=*w {
19+
// m[i, j] compiled according to the following rule:
20+
if i == 0 || j == 0 {
21+
m[i][j] = 0;
22+
} else if weights[i - 1] <= j {
23+
// If `i` is in the knapsack
24+
// Then m[i, j] is equal to the maximum value of the knapsack,
25+
// where the weight `j` is reduced by the weight of the `i-th` item and the set of admissible items plus the value `k`
26+
m[i][j] = max(values[i - 1] + m[i - 1][j - weights[i - 1]], m[i - 1][j]);
27+
} else {
28+
// If the item `i` did not get into the knapsack
29+
// Then m[i, j] is equal to the maximum cost of a knapsack with the same capacity and a set of admissible items
30+
m[i][j] = m[i - 1][j]
31+
}
32+
}
33+
}
34+
m
35+
}
36+
37+
/// knapsack_items(weights, m, i, j) returns the indices of the items of the optimal knapsack (from 1 to `n`)
38+
///
39+
/// Arguments:
40+
/// * `weights` - set of weights for each item
41+
/// * `m` - knapsack table with maximum values
42+
/// * `i` - include items 1 through `i` in knapsack (for the initial value, use `n`)
43+
/// * `j` - maximum weight of the knapsack
44+
fn knapsack_items(weights: &[usize], m: &[Vec<usize>], i: usize, j: usize) -> Vec<usize> {
45+
if i == 0 {
46+
return vec![];
47+
}
48+
if m[i][j] > m[i - 1][j] {
49+
let mut knap: Vec<usize> = knapsack_items(weights, m, i - 1, j - weights[i - 1]);
50+
knap.push(i);
51+
knap
52+
} else {
53+
knapsack_items(weights, m, i - 1, j)
54+
}
55+
}
56+
57+
/// knapsack(w, weights, values) returns the tuple where first value is `optimal profit`,
58+
/// second value is `knapsack optimal weight` and the last value is `indices of items`, that we got (from 1 to `n`)
59+
///
60+
/// Arguments:
61+
/// * `w` - knapsack capacity
62+
/// * `weights` - set of weights for each item
63+
/// * `values` - set of values for each item
64+
///
65+
/// Complexity
66+
/// - time complexity: O(nw),
67+
/// - space complexity: O(nw),
68+
///
69+
/// where `n` and `w` are `number of items` and `knapsack capacity`
70+
pub fn knapsack(w: usize, weights: Vec<usize>, values: Vec<usize>) -> (usize, usize, Vec<usize>) {
71+
// Checks if the number of items in the list of weights is the same as the number of items in the list of values
72+
assert_eq!(weights.len(), values.len(), "Number of items in the list of weights doesn't match the number of items in the list of values!");
73+
// Initialize `n` - number of items
74+
let n: usize = weights.len();
75+
// Find the knapsack table
76+
let m: Vec<Vec<usize>> = knapsack_table(&w, &weights, &values);
77+
// Find the indices of the items
78+
let items: Vec<usize> = knapsack_items(&weights, &m, n, w);
79+
// Find the total weight of optimal knapsack
80+
let mut total_weight: usize = 0;
81+
for i in items.iter() {
82+
total_weight += weights[i - 1];
83+
}
84+
// Return result
85+
(m[n][w], total_weight, items)
86+
}
87+
88+
#[cfg(test)]
89+
mod tests {
90+
// Took test datasets from https://people.sc.fsu.edu/~jburkardt/datasets/bin_packing/bin_packing.html
91+
use super::*;
92+
93+
#[test]
94+
fn test_p02() {
95+
assert_eq!(
96+
(51, 26, vec![2, 3, 4]),
97+
knapsack(26, vec![12, 7, 11, 8, 9], vec![24, 13, 23, 15, 16])
98+
);
99+
}
100+
101+
#[test]
102+
fn test_p04() {
103+
assert_eq!(
104+
(150, 190, vec![1, 2, 5]),
105+
knapsack(
106+
190,
107+
vec![56, 59, 80, 64, 75, 17],
108+
vec![50, 50, 64, 46, 50, 5]
109+
)
110+
);
111+
}
112+
113+
#[test]
114+
fn test_p01() {
115+
assert_eq!(
116+
(309, 165, vec![1, 2, 3, 4, 6]),
117+
knapsack(
118+
165,
119+
vec![23, 31, 29, 44, 53, 38, 63, 85, 89, 82],
120+
vec![92, 57, 49, 68, 60, 43, 67, 84, 87, 72]
121+
)
122+
);
123+
}
124+
125+
#[test]
126+
fn test_p06() {
127+
assert_eq!(
128+
(1735, 169, vec![2, 4, 7]),
129+
knapsack(
130+
170,
131+
vec![41, 50, 49, 59, 55, 57, 60],
132+
vec![442, 525, 511, 593, 546, 564, 617]
133+
)
134+
);
135+
}
136+
137+
#[test]
138+
fn test_p07() {
139+
assert_eq!(
140+
(1458, 749, vec![1, 3, 5, 7, 8, 9, 14, 15]),
141+
knapsack(
142+
750,
143+
vec![70, 73, 77, 80, 82, 87, 90, 94, 98, 106, 110, 113, 115, 118, 120],
144+
vec![135, 139, 149, 150, 156, 163, 173, 184, 192, 201, 210, 214, 221, 229, 240]
145+
)
146+
);
147+
}
148+
}

src/dynamic_programming/mod.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,12 @@
11
mod edit_distance;
22
mod egg_dropping;
33
mod fibonacci;
4+
mod knapsack;
45
mod longest_common_subsequence;
56

67
pub use self::edit_distance::{edit_distance, edit_distance_se};
78
pub use self::egg_dropping::egg_drop;
89
pub use self::fibonacci::fibonacci;
910
pub use self::fibonacci::recursive_fibonacci;
11+
pub use self::knapsack::knapsack;
1012
pub use self::longest_common_subsequence::longest_common_subsequence;

0 commit comments

Comments
 (0)