Add approach using linear range reduction

This commit is contained in:
2023-12-06 15:51:24 +01:00
committed by Hannes Körber
parent c9e912fbe0
commit 29ef927ae5

View File

@@ -12,7 +12,8 @@ use std::str::FromStr;
#[allow(dead_code)] #[allow(dead_code)]
enum Approach { enum Approach {
BruteForce, BruteForce,
Math, QuadraticFormula,
RangeReduction,
} }
impl FromStr for Approach { impl FromStr for Approach {
@@ -21,7 +22,8 @@ impl FromStr for Approach {
fn from_str(s: &str) -> Result<Self, Self::Err> { fn from_str(s: &str) -> Result<Self, Self::Err> {
Ok(match s { Ok(match s {
"bruteforce" => Self::BruteForce, "bruteforce" => Self::BruteForce,
"math" => Self::Math, "quadraticformula" => Self::QuadraticFormula,
"rangereduction" => Self::RangeReduction,
_ => return Err("unknown approach"), _ => return Err("unknown approach"),
}) })
} }
@@ -30,7 +32,11 @@ impl FromStr for Approach {
#[allow(dead_code)] #[allow(dead_code)]
impl Approach { impl Approach {
fn values() -> Vec<Self> { fn values() -> Vec<Self> {
vec![Self::BruteForce, Self::Math] vec![
Self::BruteForce,
Self::QuadraticFormula,
Self::RangeReduction,
]
} }
} }
@@ -61,7 +67,7 @@ impl Race {
}) })
.collect::<Vec<_>>() .collect::<Vec<_>>()
.len(), .len(),
_ => { Approach::QuadraticFormula => {
// the races form a quadratic function: // the races form a quadratic function:
// //
// T = the total time of the race // T = the total time of the race
@@ -117,6 +123,33 @@ impl Race {
0 0
} }
} }
Approach::RangeReduction => {
let limit: isize = self.distance.try_into().unwrap();
let time: isize = self.time.try_into().unwrap();
let f = |x: isize| -x * x + time * x;
// we know that charging for 0 seconds always loses, as the result will be 0
let lower_bound = 0;
assert!(f(lower_bound) == 0);
// we know that charging for the hold time of the game always loses, as the
// result will be 0
let upper_bound = self.time.try_into().unwrap();
assert!(f(upper_bound) == 0);
// linear search, this could be optimized to a binary search
let first_win = (lower_bound..upper_bound).find(|x| f(*x) > limit);
let last_win = (lower_bound..upper_bound).rev().find(|x| f(*x) > limit);
// merge the options into one,
let wins = first_win.zip(last_win);
if let Some((first, last)) = wins {
(last - first + 1).try_into().unwrap()
} else {
0
}
}
} }
} }
} }