oxicuda_graphalg/max_flow/
dinic.rs1use std::collections::VecDeque;
4
5use crate::error::{GraphalgError, GraphalgResult};
6use crate::max_flow::edmonds_karp::FlowNetwork;
7
8pub fn dinic_max_flow(net: &FlowNetwork, source: usize, sink: usize) -> GraphalgResult<f64> {
10 if source >= net.n || sink >= net.n {
11 return Err(GraphalgError::SourceOutOfRange {
12 node: source.max(sink),
13 n: net.n,
14 });
15 }
16 let mut residual = net.clone();
17 let mut max_flow = 0.0;
18 let n = net.n;
19 loop {
20 let mut level = vec![i64::MAX; n];
22 level[source] = 0;
23 let mut q: VecDeque<usize> = VecDeque::new();
24 q.push_back(source);
25 while let Some(u) = q.pop_front() {
26 for v in 0..n {
27 if level[v] == i64::MAX && residual.c(u, v) > 1e-12 {
28 level[v] = level[u] + 1;
29 q.push_back(v);
30 }
31 }
32 }
33 if level[sink] == i64::MAX {
34 break;
35 }
36 let mut next_idx = vec![0usize; n];
38 loop {
39 let pushed = dfs_push(
40 &mut residual,
41 source,
42 sink,
43 f64::INFINITY,
44 &level,
45 &mut next_idx,
46 );
47 if pushed <= 1e-15 {
48 break;
49 }
50 max_flow += pushed;
51 }
52 }
53 Ok(max_flow)
54}
55
56fn dfs_push(
57 residual: &mut FlowNetwork,
58 u: usize,
59 sink: usize,
60 pushed: f64,
61 level: &[i64],
62 next_idx: &mut [usize],
63) -> f64 {
64 if u == sink {
65 return pushed;
66 }
67 let n = residual.n;
68 while next_idx[u] < n {
69 let v = next_idx[u];
70 if residual.c(u, v) > 1e-12 && level[v] == level[u] + 1 {
71 let bottleneck = pushed.min(residual.c(u, v));
72 let res = dfs_push(residual, v, sink, bottleneck, level, next_idx);
73 if res > 1e-15 {
74 *residual.c_mut(u, v) -= res;
75 *residual.c_mut(v, u) += res;
76 return res;
77 }
78 }
79 next_idx[u] += 1;
80 }
81 0.0
82}
83
84#[cfg(test)]
85mod tests {
86 use super::*;
87
88 #[test]
89 fn dinic_simple() {
90 let mut net = FlowNetwork::new(4);
91 net.add_edge(0, 1, 3.0).expect("ok");
92 net.add_edge(0, 2, 2.0).expect("ok");
93 net.add_edge(1, 3, 3.0).expect("ok");
94 net.add_edge(2, 3, 2.0).expect("ok");
95 let f = dinic_max_flow(&net, 0, 3).expect("ok");
96 assert!((f - 5.0).abs() < 1e-9);
97 }
98}