puzzle-solver/tests/xkcd.rs
2021-12-07 20:56:04 +04:00

56 lines
1.6 KiB
Rust

//! xkcd Knapsack Problem.
//!
//! https://en.wikipedia.org/wiki/Knapsack_problem
//! https://xkcd.com/287/
extern crate num_rational;
extern crate num_traits;
extern crate puzzle_solver;
use num_rational::Ratio;
use num_traits::ToPrimitive;
use puzzle_solver::{LinExpr, Puzzle, Val};
#[test]
fn xkcd_knapsack() {
let menu = [
(Ratio::new(2_15, 100), "Mixed Fruit"),
(Ratio::new(2_75, 100), "French Fries"),
(Ratio::new(3_35, 100), "Side Salad"),
(Ratio::new(3_55, 100), "Hot Wings"),
(Ratio::new(4_20, 100), "Mozzarella Sticks"),
(Ratio::new(5_80, 100), "Sampler Plate"),
];
let mut sys = Puzzle::new();
let mut vars = Vec::with_capacity(menu.len());
let total = Ratio::new(15_05, 100);
for &(cost, _) in menu.iter() {
let num = (total / cost).floor().to_integer();
let var = sys.new_var_with_candidates(&(0..(num + 1)).collect::<Vec<Val>>());
vars.push(var)
}
sys.equals(
total,
vars.iter()
.zip(menu.iter())
.fold(LinExpr::from(0), |sum, (&var, &(cost, _))| sum + var * cost),
);
let solutions = sys.solve_all();
assert_eq!(solutions.len(), 2);
for dict in solutions.iter() {
println!("");
for (&var, &(cost, string)) in vars.iter().zip(menu.iter()) {
let numer = cost.numer().to_f32().unwrap();
let denom = cost.denom().to_f32().unwrap();
println!(" {} x {:.2} {}", dict[var], numer / denom, string);
}
}
println!("xkcd_knapsack: {} guesses", sys.num_guesses());
}