有向グラフ - 最大流量

概要

Dinic 法を実装する

入出力

重み付きの隣接リストを入力とする. すなわち, 頂点 \(u\) から \(v\) へ容量 \(c\) の辺があるとき, neigh[u] = [(v, w)] とするようなリスト neigh.

関連問題

/// Graph - Directed - Dinic's MaxFlow - O(V^2 E)
use crate::algebra::group_additive::*;
use crate::algebra::hyper::*;

pub struct Dinic<X> {
    size: usize,
    s: usize,
    t: usize,
    g: Vec<Vec<(usize, Hyper<X>)>>,
}
impl<X: std::fmt::Debug + Copy + Eq + Ord + AGroup> Dinic<X> {
    pub fn new(s: usize, t: usize, neigh: &[Vec<(usize, Hyper<X>)>]) -> Self {
        let size = neigh.len();
        let mut g = vec![vec![]; size];
        for u in 0..size {
            for &(v, cap) in neigh[u].iter() {
                g[u].push((v, cap));
                g[v].push((u, Hyper::zero()));
            }
        }
        Self { size, s, t, g }
    }
    pub fn maxflow(&self) -> Hyper<X> {
        let mut sum = Hyper::zero();
        let mut flw = vec![vec![Hyper::zero(); self.size]; self.size];
        loop {
            let level = self.levelize(&flw);
            if level[self.t] >= self.size {
                break;
            }
            sum += self.augment(Hyper::Inf, &mut flw, &level, self.s);
        }
        sum
    }
    fn levelize(&self, flw: &[Vec<Hyper<X>>]) -> Vec<usize> {
        use std::{cmp::Reverse, collections::BinaryHeap};
        let mut level = vec![self.size; self.size];
        let mut q = BinaryHeap::new();
        q.push((Reverse(0), self.s));
        level[self.s] = 0;
        while let Some((_, u)) = q.pop() {
            if u == self.t {
                break;
            }
            for &(v, cap) in self.g[u].iter() {
                if level[v] == self.size && cap > flw[u][v] {
                    level[v] = level[u] + 1;
                    q.push((Reverse(level[v]), v));
                }
            }
        }
        level
    }
    fn augment(
        &self,
        limit: Hyper<X>,
        mut flw: &mut Vec<Vec<Hyper<X>>>,
        level: &[usize],
        u: usize,
    ) -> Hyper<X> {
        if u == self.t {
            return limit;
        }
        for &(v, cap) in self.g[u].iter() {
            if level[v] > level[u] {
                let limit = std::cmp::min(limit, cap - flw[u][v]);
                let f = self.augment(limit, &mut flw, &level, v);
                if f > Hyper::zero() {
                    flw[u][v] += f;
                    flw[v][u] -= f;
                    return f;
                }
            }
        }
        Hyper::zero()
    }
}

#[cfg(test)]
mod test_dinic {
    use crate::algebra::hyper::Hyper::*;
    use crate::graph::directed::dinic::*;

    #[test]
    fn test_a() {
        let neigh = vec![
            vec![(1, Real(1)), (3, Real(1)), (5, Real(1))],
            vec![(2, Real(1)), (4, Real(1))],
            vec![(6, Real(1))],
            vec![(2, Real(1))],
            vec![(6, Real(1))],
            vec![(2, Real(1)), (4, Real(1))],
            vec![],
        ];
        assert_eq!(Dinic::new(0, 6, &neigh).maxflow(), Real(2));
    }

    #[test]
    fn test_b() {
        let neigh = vec![
            vec![(1, Real(3)), (2, Real(3))],
            vec![(2, Real(2)), (3, Real(3))],
            vec![(4, Real(2))],
            vec![(4, Real(3)), (5, Real(2))],
            vec![(5, Real(3))],
            vec![],
        ];
        assert_eq!(Dinic::new(0, 5, &neigh).maxflow(), Real(5));
    }
}