#[derive(Debug, Clone)]
pub struct SubsetSumInstance {
numbers: Vec<u64>,
target: u64,
}
impl SubsetSumInstance {
pub fn new(numbers: Vec<u64>, target: u64) -> Self {
Self { numbers, target }
}
}
pub fn solve(instance: &SubsetSumInstance, epsilon: f64) -> (Vec<usize>, u64) {
assert!(
epsilon > 0.0 && epsilon < 1.0,
"Epsilon must be between 0 and 1"
);
if instance.numbers.is_empty() {
return (Vec::new(), 0);
}
let mut best_sum = 0;
let mut best_selection = Vec::new();
for mask in 0..(1 << instance.numbers.len()) {
let mut current_sum = 0;
let mut current_selection = Vec::new();
for (i, &num) in instance.numbers.iter().enumerate() {
if (mask & (1 << i)) != 0 {
current_sum += num;
current_selection.push(i);
}
}
if current_sum == instance.target {
if best_sum != instance.target || current_selection.len() < best_selection.len() {
best_sum = current_sum;
best_selection = current_selection;
}
continue;
}
if current_sum <= instance.target && current_sum > best_sum {
best_sum = current_sum;
best_selection = current_selection;
}
}
(best_selection, best_sum)
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_simple_subset_sum() {
let numbers = vec![1, 2, 3, 4, 5];
let target = 7;
let instance = SubsetSumInstance::new(numbers, target);
let (selected, sum) = solve(&instance, 0.1);
assert!(sum <= target);
assert!(sum as f64 >= 0.9 * target as f64);
let actual_sum: u64 = selected.iter().map(|&i| instance.numbers[i]).sum();
assert_eq!(sum, actual_sum);
}
#[test]
fn test_exact_target() {
let numbers = vec![2, 3, 5];
let target = 5;
let instance = SubsetSumInstance::new(numbers, target);
let (selected, sum) = solve(&instance, 0.1);
assert_eq!(sum, target);
assert_eq!(selected.len(), 1);
assert_eq!(instance.numbers[selected[0]], 5);
}
#[test]
fn test_empty_instance() {
let instance = SubsetSumInstance::new(Vec::new(), 10);
let (selected, sum) = solve(&instance, 0.1);
assert!(selected.is_empty());
assert_eq!(sum, 0);
}
}