Skip to content

Commit

Permalink
Add problem 2188: Minimum Time to Finish the Race
Browse files Browse the repository at this point in the history
  • Loading branch information
EFanZh committed Oct 8, 2024
1 parent ba4b24d commit a4d8a9d
Show file tree
Hide file tree
Showing 3 changed files with 133 additions and 0 deletions.
1 change: 1 addition & 0 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,103 @@
pub struct Solution;

// ------------------------------------------------------ snip ------------------------------------------------------ //

impl Solution {
pub fn minimum_finish_time(tires: Vec<Vec<i32>>, 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<Vec<i32>>, 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::<super::Solution>();
}
}
29 changes: 29 additions & 0 deletions src/problem_2188_minimum_time_to_finish_the_race/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
pub mod dynamic_programming;

pub trait Solution {
fn minimum_finish_time(tires: Vec<Vec<i32>>, change_time: i32, num_laps: i32) -> i32;
}

#[cfg(test)]
mod tests {
use super::Solution;

pub fn run<S: Solution>() {
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,
);
}
}
}

0 comments on commit a4d8a9d

Please sign in to comment.