Skip to content

Commit

Permalink
Add problem 2065: Maximum Path Quality of a Graph
Browse files Browse the repository at this point in the history
  • Loading branch information
EFanZh committed Sep 22, 2024
1 parent 9da8d3c commit 2b5476a
Show file tree
Hide file tree
Showing 3 changed files with 909 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 @@ -1539,6 +1539,7 @@ pub mod problem_2059_minimum_operations_to_convert_number;
pub mod problem_2062_count_vowel_substrings_of_a_string;
pub mod problem_2063_vowels_of_all_substrings;
pub mod problem_2064_minimized_maximum_of_products_distributed_to_any_store;
pub mod problem_2065_maximum_path_quality_of_a_graph;
pub mod problem_2068_check_whether_two_strings_are_almost_equivalent;
pub mod problem_2069_walking_robot_simulation_ii;
pub mod problem_2070_most_beautiful_item_for_each_query;
Expand Down
185 changes: 185 additions & 0 deletions src/problem_2065_maximum_path_quality_of_a_graph/brute_force_dfs.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,185 @@
pub struct Solution;

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

use std::cmp::Ordering;
use std::collections::BinaryHeap;

struct Node {
value: u32,
children: [u16; 4],
children_distances: [u8; 4],
children_length: u8,
distance: u8,
}

struct Item {
distance: u8,
node: u16,
}

impl PartialEq for Item {
fn eq(&self, other: &Self) -> bool {
self.cmp(other) == Ordering::Equal
}
}

impl Eq for Item {}

impl PartialOrd for Item {
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
Some(self.cmp(other))
}
}

impl Ord for Item {
fn cmp(&self, other: &Self) -> Ordering {
other.distance.cmp(&self.distance)
}
}

struct ContextMut {
used_nodes: Vec<u16>,
result: u32,
}

impl Solution {
fn dfs(nodes: &[Node], context_mut: &mut ContextMut, node: &Node, budget_time: u8, quality: u32) {
for (&child, &edge_time) in node
.children
.iter()
.zip(&node.children_distances)
.take(usize::from(node.children_length))
{
let child_node = &nodes[usize::from(child)];

if budget_time >= edge_time + child_node.distance {
if child == 0 {
context_mut.result = context_mut.result.max(quality);
}

let (need_to_pop, child_quality) = if context_mut.used_nodes.contains(&child) {
(false, quality)
} else {
context_mut.used_nodes.push(child);

(true, quality + child_node.value)
};

Self::dfs(nodes, context_mut, child_node, budget_time - edge_time, child_quality);

if need_to_pop {
context_mut.used_nodes.pop();
}
}
}
}

pub fn maximal_path_quality(values: Vec<i32>, edges: Vec<Vec<i32>>, max_time: i32) -> i32 {
let max_time = max_time as u8;

let mut nodes = values
.into_iter()
.map(|value| Node {
value: value as _,
children: [0; 4],
children_distances: [0; 4],
children_length: 0,
distance: max_time,
})
.collect::<Vec<_>>();

for edge in edges {
let [from, to, time] = <[_; 3]>::map(edge.try_into().ok().unwrap(), |x| x as u32);

for (from, to) in [(from, to), (to, from)] {
let from_node = &mut nodes[from as usize];

from_node.children[usize::from(from_node.children_length)] = to as _;
from_node.children_distances[usize::from(from_node.children_length)] = time as _;
from_node.children_length += 1;
}
}

nodes[0].distance = 0;

let mut queue = BinaryHeap::new();
let mut item = Item { distance: 0, node: 0 };
let mut children_buffer;
let mut children_distance_buffer;

'outer: loop {
let node = &nodes[usize::from(item.node)];

children_buffer = node.children;
children_distance_buffer = node.children_distances;

for (&child, &time) in children_buffer
.iter()
.zip(&children_distance_buffer)
.take(usize::from(node.children_length))
{
let candidate = item.distance + time;

if candidate < max_time {
let child_node = &mut nodes[usize::from(child)];

if candidate < child_node.distance {
child_node.distance = candidate;

queue.push(Item {
distance: candidate,
node: child,
});
}
}
}

loop {
if let Some(next) = queue.pop() {
if next.distance == nodes[usize::from(next.node)].distance {
item = next;

break;
}
} else {
break 'outer;
}
}
}

let node = nodes.first().unwrap();

let mut context_mut = ContextMut {
used_nodes: vec![0],
result: node.value,
};

Self::dfs(&nodes, &mut context_mut, node, max_time, node.value);

context_mut.result as _
}
}

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

impl super::Solution for Solution {
fn maximal_path_quality(values: Vec<i32>, edges: Vec<Vec<i32>>, max_time: i32) -> i32 {
Self::maximal_path_quality(values, edges, max_time)
}
}

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

#[test]
fn test_item_partial_eq() {
assert!(Item { distance: 2, node: 3 } == Item { distance: 2, node: 5 });
}

#[test]
fn test_solution() {
super::super::tests::run::<super::Solution>();
}
}
Loading

0 comments on commit 2b5476a

Please sign in to comment.