From a4d8a9d4c8214c5977892d3edfa18f699d365710 Mon Sep 17 00:00:00 2001 From: EFanZh Date: Tue, 8 Oct 2024 21:35:54 +0800 Subject: [PATCH] Add problem 2188: Minimum Time to Finish the Race --- src/lib.rs | 1 + .../dynamic_programming.rs | 103 ++++++++++++++++++ .../mod.rs | 29 +++++ 3 files changed, 133 insertions(+) create mode 100644 src/problem_2188_minimum_time_to_finish_the_race/dynamic_programming.rs create mode 100644 src/problem_2188_minimum_time_to_finish_the_race/mod.rs diff --git a/src/lib.rs b/src/lib.rs index 7a082f5a..0733cbf0 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1633,6 +1633,7 @@ pub mod problem_2183_count_array_pairs_divisible_by_k; pub mod problem_2185_counting_words_with_a_given_prefix; pub mod problem_2186_minimum_number_of_steps_to_make_two_strings_anagram_ii; pub mod problem_2187_minimum_time_to_complete_trips; +pub mod problem_2188_minimum_time_to_finish_the_race; pub mod problem_2190_most_frequent_number_following_key_in_an_array; pub mod problem_2191_sort_the_jumbled_numbers; pub mod problem_2192_all_ancestors_of_a_node_in_a_directed_acyclic_graph; diff --git a/src/problem_2188_minimum_time_to_finish_the_race/dynamic_programming.rs b/src/problem_2188_minimum_time_to_finish_the_race/dynamic_programming.rs new file mode 100644 index 00000000..fe5b718e --- /dev/null +++ b/src/problem_2188_minimum_time_to_finish_the_race/dynamic_programming.rs @@ -0,0 +1,103 @@ +pub struct Solution; + +// ------------------------------------------------------ snip ------------------------------------------------------ // + +impl Solution { + pub fn minimum_finish_time(tires: Vec>, change_time: i32, num_laps: i32) -> i32 { + const QUEUE_BITS: u8 = 5; + + let change_time = change_time as u32; + let num_laps = num_laps as u32 as usize; + let mut min_times = [u32::MAX; 16]; + + for tire in tires { + let [f, r] = <[_; 2]>::map(tire.try_into().ok().unwrap(), |x| x as u32); + + let first_min_time = min_times.first_mut().unwrap(); + + (*first_min_time) = (*first_min_time).min(f); + + let mut prev_lap_time = f; + let mut prev_lap_time_sum = f; + let mut half_lap_time = f; + let mut half_lap_time_sum = f; + let mut is_odd_lap = false; + + let max_laps = min_times.len().min(num_laps); + + for target in &mut min_times[1..max_laps] { + if let Some((lap_time, lap_time_sum)) = prev_lap_time.checked_mul(r).and_then(|lap_time| { + prev_lap_time_sum + .checked_add(lap_time) + .map(|lap_time_sum| (lap_time, lap_time_sum)) + }) { + let saved_half_lap_time_sum = half_lap_time_sum; + + if is_odd_lap { + half_lap_time *= r; + half_lap_time_sum += half_lap_time; + }; + + let other_lap_time_sum = saved_half_lap_time_sum + half_lap_time_sum; + + if lap_time_sum - other_lap_time_sum < change_time { + *target = (*target).min(lap_time_sum); + + prev_lap_time = lap_time; + prev_lap_time_sum += lap_time; + is_odd_lap = !is_odd_lap; + + continue; + } + } + + break; + } + } + + let max_laps = min_times.iter().take_while(|&&time| time != u32::MAX).count(); + let mut queue = [0; (1 << QUEUE_BITS)]; + let queue_mask = queue.len() - 1; + let mut total_laps = 0_usize; + + queue[0] = change_time.wrapping_neg(); + + loop { + total_laps += 1; + + let min_time = (1..).zip(&min_times[..total_laps.min(max_laps)]).fold( + u32::MAX, + |min_time, (last_laps, &last_laps_time)| { + min_time.min( + queue[total_laps.wrapping_sub(last_laps as usize) & queue_mask].wrapping_add(change_time) + + last_laps_time, + ) + }, + ); + + queue[total_laps & queue_mask] = min_time; + + if total_laps == num_laps { + break; + } + } + + queue[total_laps & queue_mask] as _ + } +} + +// ------------------------------------------------------ snip ------------------------------------------------------ // + +impl super::Solution for Solution { + fn minimum_finish_time(tires: Vec>, change_time: i32, num_laps: i32) -> i32 { + Self::minimum_finish_time(tires, change_time, num_laps) + } +} + +#[cfg(test)] +mod tests { + #[test] + fn test_solution() { + super::super::tests::run::(); + } +} diff --git a/src/problem_2188_minimum_time_to_finish_the_race/mod.rs b/src/problem_2188_minimum_time_to_finish_the_race/mod.rs new file mode 100644 index 00000000..6b6a454a --- /dev/null +++ b/src/problem_2188_minimum_time_to_finish_the_race/mod.rs @@ -0,0 +1,29 @@ +pub mod dynamic_programming; + +pub trait Solution { + fn minimum_finish_time(tires: Vec>, change_time: i32, num_laps: i32) -> i32; +} + +#[cfg(test)] +mod tests { + use super::Solution; + + pub fn run() { + let test_cases = [ + ((&[[2, 3], [3, 4]] as &[_], 5, 4), 21), + ((&[[1, 10], [2, 2], [3, 4]], 6, 5), 25), + ( + (&[[1, 2], [1, 3], [1, 4], [1, 5], [1, 6], [1, 7]], 100_000, 1000), + 8_214_040, + ), + ((&[[100_000, 100_000]], 100_000, 1000), 199_900_000), + ]; + + for ((tires, change_time, num_laps), expected) in test_cases { + assert_eq!( + S::minimum_finish_time(tires.iter().map(Vec::from).collect(), change_time, num_laps), + expected, + ); + } + } +}