#[cfg(not(feature = "std"))]
use alloc::{
collections::BinaryHeap,
vec::Vec,
};
#[cfg(feature = "std")]
use std::{
collections::BinaryHeap,
hash::Hash
};
#[cfg(feature = "std")]
type IndexMap<K, V> = indexmap::IndexMap<K, V>;
#[cfg(not(feature = "std"))]
type IndexMap<K, V> = indexmap::IndexMap<K, V, core::hash::BuildHasherDefault<twox_hash::XxHash64>>;
#[cfg(not(feature = "std"))]
use core::hash::Hash;
use super::visit::{EdgeRef, IntoEdges, NodeCount, NodeIndexable, Visitable};
use crate::{
algo::Measure,
scored::MinScored
};
pub fn k_shortest_path<G, F, K>(
graph: G,
start: G::NodeId,
goal: Option<G::NodeId>,
k: usize,
mut edge_cost: F,
) -> IndexMap<G::NodeId, K>
where
G: IntoEdges + Visitable + NodeCount + NodeIndexable,
G::NodeId: Eq + Hash + Ord,
F: FnMut(G::EdgeRef) -> K,
K: Measure + Copy,
{
let mut counter: Vec<usize> = vec![0; graph.node_count()];
let mut scores = IndexMap::default();
let mut visit_next = BinaryHeap::new();
let zero_score = K::default();
visit_next.push(MinScored(zero_score, start));
while let Some(MinScored(node_score, node)) = visit_next.pop() {
counter[graph.to_index(node)] += 1;
let current_counter = counter[graph.to_index(node)];
if current_counter > k {
continue;
}
if current_counter == k {
scores.insert(node, node_score);
}
if goal.as_ref() == Some(&node) && current_counter == k {
break;
}
for edge in graph.edges(node) {
visit_next.push(MinScored(node_score + edge_cost(edge), edge.target()));
}
}
scores
}