-
Notifications
You must be signed in to change notification settings - Fork 14
/
Copy pathknapsack.rs
96 lines (83 loc) · 2.42 KB
/
knapsack.rs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
use russcip::minimal_model;
use russcip::prelude::*;
/// 0-1 Knapsack problem
#[derive(Debug)]
struct Knapsack {
/// Sizes of the items
sizes: Vec<usize>,
/// Values of the items
values: Vec<usize>,
/// Capacity of the knapsack
capacity: usize,
}
/// Solution to the knapsack problem
#[derive(Debug)]
struct KnapsackSolution {
/// Indices of the items in the solution
items: Vec<usize>,
/// Total value of the solution
value: f64,
}
impl Knapsack {
fn new(sizes: Vec<usize>, values: Vec<usize>, capacity: usize) -> Self {
assert_eq!(
sizes.len(),
values.len(),
"Sizes and values must have the same length"
);
Knapsack {
sizes,
values,
capacity,
}
}
/// Solves the 0-1 knapsack as an integer program
fn solve(&self) -> KnapsackSolution {
let mut model = minimal_model().maximize();
let mut vars = Vec::with_capacity(self.sizes.len());
for i in 0..self.sizes.len() {
vars.push(model.add(var().bin().obj(self.values[i] as f64)));
}
let mut capacity_cons = cons().le(self.capacity as f64);
for (i, var) in vars.iter().enumerate() {
capacity_cons = capacity_cons.coef(var, self.sizes[i] as f64);
}
model.add(capacity_cons);
let solved_model = model.solve();
let sol = solved_model.best_sol().unwrap();
let mut items = vec![];
for (i, var) in vars.iter().enumerate() {
if sol.val(var) > 0.5 {
items.push(i);
}
}
let value = sol.obj_val();
KnapsackSolution { items, value }
}
}
fn main() {
let knapsack = Knapsack::new(vec![2, 3, 4, 5], vec![3, 4, 5, 6], 6);
let solution = knapsack.solve();
println!("Input: {:?}", knapsack);
println!("Solution items: {:?}", solution.items);
println!(
"Value: {} = {:?}",
solution.value,
solution
.items
.iter()
.map(|&i| (knapsack.sizes[i], knapsack.values[i]))
.collect::<Vec<_>>()
);
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_knapsack() {
let knapsack = Knapsack::new(vec![2, 3, 4, 5], vec![3, 4, 5, 6], 6);
let solution = knapsack.solve();
assert_eq!(solution.items, vec![0, 2]);
assert_eq!(solution.value.round(), 8.0);
}
}