Given a set of items with a weight and a value, this problem gives the subset of items which maximize value so that their combined weights is less or equal than a given maximum weight. This solution runs in \$O(w\cdot n)\$ where \$n\$ is the number of items and \$w\$ is the max weight.
#[derive(Debug, Clone)]
struct Item {
value: usize,
weight: usize,
}
impl Item {
fn new(pvalue: usize, pweight: usize) -> Item {
Item { value: pvalue, weight: pweight }
}
}
#[derive(Debug, Clone)]
struct Info {
ks_value: usize,
added_weight: usize,
included: bool,
}
impl Info {
fn new(pks_value: usize, padded_weight: usize, pincluded: bool) -> Info{
Info {
ks_value: pks_value,
added_weight: padded_weight,
included: pincluded,
}
}
}
impl std::cmp::Ord for Info {
fn cmp(&self, other: &Info) -> std::cmp::Ordering {
self.ks_value.cmp(&other.ks_value)
}
}
impl PartialOrd for Info {
fn partial_cmp(&self, other: &Info) -> Option<std::cmp::Ordering> {
Some(self.cmp(other))
}
}
impl PartialEq for Info {
fn eq(&self, other: &Info) -> bool {
self.ks_value == other.ks_value
}
}
impl Eq for Info {}
fn _0_1_knapsack_items<'a>(items: &'a[Item], max_weight: usize, subproblems: &[Vec<Info>]) -> Vec<&'a Item>{
(1..items.len() + 1).rev()
.scan(max_weight, |w, i| {
let sub = &subproblems[i][*w];
let result = (i, sub.included);
*w -= sub.added_weight;
Some(result)
})
.filter(|&(_, inc)| inc)
.take_while(|&(i, _)| i > 0)
.map(|(i, _)| &items[i - 1])
.collect::<Vec<&Item>>()
}
fn _0_1_knapsack<'a>(items: &'a [Item], max_weight: usize) -> Vec<&'a Item>{
let mut subproblems = vec! [ vec! [ Info::new(0, 0, false);
max_weight + 1 ];
items.len() + 1 ];
for i in 0..items.len() {
for w in 0..max_weight + 1 {
let w_i = items[i].weight;
let exc_cost = subproblems[i][w].ks_value;
subproblems[i + 1][w] = if w < w_i {
Info::new(exc_cost, 0, false)
}
else {
let inc_cost = subproblems[i][w - w_i].ks_value
+ items[i].value;
std::cmp::max(Info::new(exc_cost, 0, false),
Info::new(inc_cost, w_i, true))
}
}
}
_0_1_knapsack_items(items, max_weight, &subproblems)
}
fn main() {
let items = [ Item::new(92, 23), //1
Item::new(57, 31), //1
Item::new(49, 29), //1
Item::new(68, 44), //1
Item::new(60, 53), //0
Item::new(43, 38), //1
Item::new(67, 63), //0
Item::new(84, 85), //0
Item::new(87, 89), //0
Item::new(72, 82) ];//0
for i in _0_1_knapsack(&items, 165){
println!("{:?}", i);
}
}