use crate::grid::Point; use std::collections::HashMap;
use ordered_float::OrderedFloat;
use std::collections::BinaryHeap;
#[derive(Debug, Clone)]
pub struct Edge {
pub to: Point,
pub capacity: u64,
pub cost: f64, pub flow: u64,
}
#[derive(Debug)]
pub struct Graph {
pub adj: HashMap<Point, Vec<Edge>>,
pub source: Point,
pub sink: Point,
}
impl Graph {
pub fn new(source: Point, sink: Point) -> Self {
Graph {
adj: HashMap::new(),
source,
sink,
}
}
pub fn add_node(&mut self, node: Point) {
self.adj.entry(node).or_insert_with(Vec::new);
}
pub fn add_edge(&mut self, from: Point, to: Point, capacity: u64, cost: f64) { self.add_node(from);
self.add_node(to);
self.adj.get_mut(&from).unwrap().push(Edge {
to,
capacity,
cost,
flow: 0,
});
}
pub fn get_edges(&self, node: &Point) -> &Vec<Edge> {
self.adj.get(node).unwrap_or_else(|| {
static EMPTY_VEC: Vec<Edge> = Vec::new();
&EMPTY_VEC
})
}
fn find_cheapest_path_dijkstra(&self) -> (HashMap<Point, Point>, bool) {
let mut distances: HashMap<Point, f64> = HashMap::new();
let mut parent_map = HashMap::new();
let mut pq = BinaryHeap::new();
distances.insert(self.source, 0.0);
pq.push((OrderedFloat(-0.0), self.source));
while let Some((cost, u)) = pq.pop() {
let cost = -cost.into_inner();
if cost > *distances.get(&u).unwrap_or(&f64::MAX) {
continue;
}
if u == self.sink {
return (parent_map, true);
}
for edge in self.get_edges(&u) {
if edge.capacity > edge.flow {
let new_dist = cost + edge.cost;
if new_dist < *distances.get(&edge.to).unwrap_or(&f64::MAX) {
distances.insert(edge.to, new_dist);
pq.push((OrderedFloat(-new_dist), edge.to));
parent_map.insert(edge.to, u);
}
}
}
}
(parent_map, distances.contains_key(&self.sink))
}
pub fn edmonds_karp(&mut self) -> u64 {
let mut max_flow = 0;
loop {
let (parent_map, sink_found) = self.find_cheapest_path_dijkstra();
if !sink_found {
break; }
let mut path_flow = u64::MAX;
let mut current = self.sink;
while current != self.source {
let prev = parent_map[¤t];
let edge = self.adj.get(&prev).unwrap().iter()
.find(|e| e.to == current).unwrap();
path_flow = path_flow.min(edge.capacity - edge.flow);
current = prev;
}
max_flow += path_flow;
let mut v = self.sink;
while v != self.source {
let u = parent_map[&v];
if let Some(edge) = self.adj.get_mut(&u).unwrap().iter_mut()
.find(|e| e.to == v) {
edge.flow += path_flow;
}
v = u;
}
}
max_flow
}
pub fn route_cheapest_path(&mut self) -> (u64, Option<Vec<Point>>) {
let (parent_map, sink_found) = self.find_cheapest_path_dijkstra();
if !sink_found {
return (0, None);
}
let mut path = vec![self.sink];
let mut current = self.sink;
while current != self.source {
current = parent_map[¤t];
path.push(current);
}
path.reverse();
let path_clone = path.clone();
let mut path_flow = u64::MAX;
for i in 0..path.len() - 1 {
let u = path[i];
let v = path[i+1];
let edge = self.adj.get(&u).unwrap().iter().find(|e| e.to == v).unwrap();
path_flow = path_flow.min(edge.capacity - edge.flow);
}
for i in 0..path.len() - 1 {
let u = path[i];
let v = path[i+1];
if let Some(edge) = self.adj.get_mut(&u).unwrap().iter_mut().find(|e| e.to == v) {
edge.flow += path_flow;
}
}
(path_flow, Some(path_clone))
}
}