use gdsl::{digraph::*, digraph_connect as connect, digraph_node as node};
use std::cell::Cell;
use std::rc::{Rc, Weak};
type N = Node<usize, (), FlowEdge>;
type G = Graph<usize, (), FlowEdge>;
#[derive(Clone, Copy)]
struct Flow(u64, u64);
#[derive(Clone)]
struct FlowEdge(Rc<Cell<Flow>>, Weak<Cell<Flow>>);
impl FlowEdge {
fn connect(s: &N, t: &N, max: u64) {
let mut fflow = FlowEdge(Rc::new(Cell::new(Flow(max, 0))), Weak::new());
let mut rflow = FlowEdge(Rc::new(Cell::new(Flow(max, max))), Weak::new());
fflow.1 = Rc::downgrade(&rflow.0);
rflow.1 = Rc::downgrade(&fflow.0);
connect!(s => t, fflow);
connect!(t => s, rflow);
}
fn update(&self, aug_flow: u64) {
let (fflow, rflow) = (&self.0, &self.1.upgrade().unwrap());
let Flow(fmax, fcur) = fflow.get();
let Flow(rmax, rcur) = rflow.get();
fflow.set(Flow(fmax, fcur + aug_flow));
rflow.set(Flow(rmax, rcur - aug_flow));
}
fn max(&self) -> u64 {
self.0.get().0
}
fn cur(&self) -> u64 {
self.0.get().1
}
}
fn max_flow(g: &G) -> u64 {
let mut max_flow: u64 = 0;
while let Some(path) = g[0]
.dfs()
.target(&5)
.filter(&mut |Edge(_, _, e)| e.cur() < e.max())
.search_path()
{
let mut aug_flow = std::u64::MAX;
for Edge(_, _, flow) in path.iter_edges() {
if flow.max() - flow.cur() < aug_flow {
aug_flow = flow.max() - flow.cur();
}
}
for Edge(_, _, flow) in path.iter_edges() {
flow.update(aug_flow);
}
max_flow += aug_flow;
}
max_flow
}
fn main() {
let mut g = Graph::new();
g.insert(node!(0));
g.insert(node!(1));
g.insert(node!(2));
g.insert(node!(3));
g.insert(node!(4));
g.insert(node!(5));
FlowEdge::connect(&g[0], &g[1], 16);
FlowEdge::connect(&g[0], &g[2], 13);
FlowEdge::connect(&g[1], &g[2], 10);
FlowEdge::connect(&g[1], &g[3], 12);
FlowEdge::connect(&g[2], &g[1], 4);
FlowEdge::connect(&g[2], &g[4], 14);
FlowEdge::connect(&g[3], &g[2], 9);
FlowEdge::connect(&g[3], &g[5], 20);
FlowEdge::connect(&g[4], &g[3], 7);
FlowEdge::connect(&g[4], &g[5], 4);
assert!(max_flow(&g) == 23);
}