// template {{{
#![allow(clippy::many_single_char_names)]

#[allow(dead_code)]
mod ngtio {
    use ::std::collections::VecDeque;

    pub struct Buffer {
        buf: VecDeque<String>,
    }

    impl Buffer {
        pub fn new() -> Self {
            Self {
                buf: VecDeque::new(),
            }
        }

        fn load(&mut self) {
            while self.buf.is_empty() {
                let mut s = String::new();
                let length = ::std::io::stdin().read_line(&mut s).unwrap();
                if length == 0 {
                    break;
                }
                self.buf.extend(s.split_whitespace().map(|s| s.to_owned()));
            }
        }

        pub fn string(&mut self) -> String {
            self.load();
            self.buf
                .pop_front()
                .unwrap_or_else(|| panic!("入力が終了したのですが。"))
        }

        pub fn string_char_vec(&mut self) -> Vec<char> {
            let s = self.string();
            s.chars().collect::<Vec<_>>()
        }

        pub fn string_char_vec_trusted_len(&mut self, len: usize) -> Vec<char> {
            let s = self.string();
            let s = s.chars().collect::<Vec<_>>();
            assert_eq!(s.len(), len, "あら、思ったのと長さ違いますね……");
            s
        }

        pub fn char(&mut self) -> char {
            let string = self.string();
            let mut chars = string.chars();
            let res = chars.next().unwrap();
            assert!(
                chars.next().is_none(),
                "char で受け取りたいのも山々なのですが、さては 2 文字以上ありますね？"
            );
            res
        }

        pub fn read<T: ::std::str::FromStr>(&mut self) -> T
        where
            <T as ::std::str::FromStr>::Err: ::std::fmt::Debug,
        {
            self.string()
                .parse::<T>()
                .expect("Failed to parse the input.")
        }

        pub fn read_vec<T: ::std::str::FromStr>(&mut self, len: usize) -> Vec<T>
        where
            <T as ::std::str::FromStr>::Err: ::std::fmt::Debug,
        {
            (0..len).map(|_| self.read::<T>()).collect()
        }
    }

    macro_rules! define_primitive_reader {
        ($($ty:tt,)*) => {
            impl Buffer {
                $(
#[inline]
                    pub fn $ty(&mut self) -> $ty {
                        self.read::<$ty>()
                    }
                )*
            }
        }
    }

    define_primitive_reader! {
        u8, u16, u32, u64, usize,
        i8, i16, i32, i64, isize,
    }

    impl Default for Buffer {
        fn default() -> Self {
            Self::new()
        }
    }
}

#[allow(unused_imports)]
use std::{collections, iter, mem, ops};
// }}}
// seq {{{
#[allow(dead_code)]
mod seq {
    #![warn(missing_docs, missing_doc_code_examples)]

    pub use self::accumulate::{accumulate, Accumulate};
    pub use self::adjacent::{adjacent, Adjacent};
    pub use self::cartesian_product::{cartesian_product, CartesianProduct};
    pub use self::format_intersparse::format_intersparse;
    pub use self::grid_next::{grid_next, GridNext};
    pub use self::intersperse::{intersperse, Intersperse};
    pub use self::mul_step::{mul_step, MulStep};
    pub use self::repeat_with::{repeat_with, RepeatWith};
    pub use self::step::{step, Step};

    use std::{fmt, ops};

    impl<I: Iterator> Seq for I {}

    pub trait Seq: Iterator + Sized {
        fn adjacent(self) -> Adjacent<Self, Self::Item>
        where
            Self::Item: Clone,
        {
            adjacent(self)
        }

        fn grid_next(self, ij: (usize, usize), h: usize, w: usize) -> GridNext<Self>
        where
            Self: Iterator<Item = (i64, i64)>,
        {
            grid_next(self, ij, h, w)
        }

        fn cartesian_product<J>(self, other: J) -> CartesianProduct<Self, J::IntoIter>
        where
            Self: Sized,
            Self::Item: Clone,
            J: IntoIterator,
            J::IntoIter: Clone,
        {
            cartesian_product::cartesian_product(self, other.into_iter())
        }

        fn accumulate<T>(self, init: T) -> Accumulate<Self, T>
        where
            T: Clone + ops::AddAssign<Self::Item>,
        {
            accumulate::accumulate(self, init)
        }

        fn intersperse(self, elt: Self::Item) -> Intersperse<Self> {
            intersperse::intersperse(self, elt)
        }

        fn format_intersparse<T>(self, separator: T) -> String
        where
            Self::Item: fmt::Display,
            T: fmt::Display,
        {
            self.map(|x| format!("{}", x))
                .intersperse(format!("{}", separator))
                .collect::<String>()
        }
    }

    mod adjacent {
        #[allow(missing_docs)]
        pub fn adjacent<I, T>(mut iter: I) -> Adjacent<I, T>
        where
            I: Iterator<Item = T>,
            T: Clone,
        {
            if let Some(first) = iter.next() {
                Adjacent {
                    iter,
                    prv: Some(first),
                }
            } else {
                Adjacent { iter, prv: None }
            }
        }

        #[allow(missing_docs)]
        pub struct Adjacent<I, T>
        where
            I: Iterator<Item = T>,
        {
            iter: I,
            prv: Option<T>,
        }

        impl<I, T> Iterator for Adjacent<I, T>
        where
            I: Iterator<Item = T>,
            T: Clone,
        {
            type Item = (T, T);

            fn next(&mut self) -> Option<(T, T)> {
                self.prv.as_ref().cloned().and_then(|first| {
                    self.iter.next().map(|second| {
                        self.prv = Some(second.clone());
                        (first, second)
                    })
                })
            }
        }
    }

    mod grid_next {
        #[allow(missing_docs)]
        pub fn grid_next<T>(difference: T, ij: (usize, usize), h: usize, w: usize) -> GridNext<T>
        where
            T: Iterator<Item = (i64, i64)>,
        {
            GridNext {
                i: ij.0 as i64,
                j: ij.1 as i64,
                h: h as i64,
                w: w as i64,
                difference,
            }
        }

        #[allow(missing_docs)]
        #[derive(Debug, Clone)]
        pub struct GridNext<T> {
            i: i64,
            j: i64,
            h: i64,
            w: i64,
            difference: T,
        }

        impl<T> Iterator for GridNext<T>
        where
            T: Iterator<Item = (i64, i64)>,
        {
            type Item = (usize, usize);

            fn next(&mut self) -> Option<(usize, usize)> {
                while let Some((di, dj)) = self.difference.next() {
                    let ni = self.i + di;
                    let nj = self.j + dj;
                    if 0 <= ni && ni < self.h && 0 <= nj && nj < self.w {
                        return Some((ni as usize, nj as usize));
                    }
                }
                None
            }
        }
    }

    mod step {
        #[allow(missing_docs)]
        pub fn step<T, U>(init: T, step: U) -> Step<T, U>
        where
            T: Copy,
            U: Copy,
            T: ::std::ops::Add<U, Output = T>,
        {
            Step { now: init, step }
        }

        #[allow(missing_docs)]
        #[derive(Debug, Clone)]
        pub struct Step<T, U> {
            now: T,
            step: U,
        }

        #[allow(missing_docs)]
        impl<T, U> Iterator for Step<T, U>
        where
            T: Copy,
            U: Copy,
            T: ::std::ops::Add<U, Output = T>,
        {
            type Item = T;

            fn next(&mut self) -> Option<T> {
                let next = self.now + self.step;
                Some(::std::mem::replace(&mut self.now, next))
            }
        }
    }

    mod mul_step {
        #[allow(missing_docs)]
        pub fn mul_step<T, U>(init: T, step: U) -> MulStep<T, U>
        where
            T: Copy,
            U: Copy,
            T: ::std::ops::Mul<U, Output = T>,
        {
            MulStep { now: init, step }
        }

        #[allow(missing_docs)]
        #[derive(Debug, Clone)]
        pub struct MulStep<T, U> {
            now: T,
            step: U,
        }

        #[allow(missing_docs)]
        impl<T, U> Iterator for MulStep<T, U>
        where
            T: Copy,
            U: Copy,
            T: ::std::ops::Mul<U, Output = T>,
        {
            type Item = T;

            fn next(&mut self) -> Option<T> {
                let next = self.now * self.step;
                Some(::std::mem::replace(&mut self.now, next))
            }
        }
    }

    mod repeat_with {
        #[allow(missing_docs)]
        pub fn repeat_with<A, F: FnMut() -> A>(repeater: F) -> RepeatWith<F> {
            RepeatWith { repeater }
        }

        #[allow(missing_docs)]
        #[derive(Debug, Clone)]
        pub struct RepeatWith<F> {
            repeater: F,
        }

        impl<A, F: FnMut() -> A> Iterator for RepeatWith<F> {
            type Item = A;

            #[inline]
            fn next(&mut self) -> Option<A> {
                Some((self.repeater)())
            }

            #[inline]
            fn size_hint(&self) -> (usize, Option<usize>) {
                (::std::usize::MAX, None)
            }
        }
    }

    mod accumulate {
        use super::*;

        #[allow(missing_docs)]
        #[derive(Debug, Clone)]
        pub struct Accumulate<I, T> {
            prev: Option<T>,
            iter: I,
        }

        #[allow(missing_docs)]
        pub fn accumulate<I, T>(iter: I, init: T) -> Accumulate<I, T>
        where
            I: Iterator,
            T: Clone + ops::AddAssign<I::Item>,
        {
            Accumulate {
                prev: Some(init),
                iter,
            }
        }

        impl<I, T> Iterator for Accumulate<I, T>
        where
            I: Iterator,
            T: Clone + ops::AddAssign<I::Item>,
        {
            type Item = T;

            fn next(&mut self) -> Option<T> {
                let res = self.prev.clone();
                if let Some(prev) = self.prev.as_mut() {
                    if let Some(next) = self.iter.next() {
                        *prev += next;
                    } else {
                        self.prev = None;
                    }
                }
                res
            }

            fn size_hint(&self) -> (usize, Option<usize>) {
                size_hint::add_scalar(self.iter.size_hint(), 1)
            }
        }
    }

    mod cartesian_product {
        #[allow(missing_docs)]
        #[derive(Debug, Clone)]
        pub struct CartesianProduct<I, J>
        where
            I: Iterator,
        {
            a: I,
            a_cur: Option<I::Item>,
            b: J,
            b_orig: J,
        }

        #[allow(missing_docs)]
        pub fn cartesian_product<I, J>(mut i: I, j: J) -> CartesianProduct<I, J>
        where
            I: Iterator,
            J: Clone + Iterator,
            I::Item: Clone,
        {
            CartesianProduct {
                a_cur: i.next(),
                a: i,
                b_orig: j.clone(),
                b: j,
            }
        }

        impl<I, J> Iterator for CartesianProduct<I, J>
        where
            I: Iterator,
            J: Clone + Iterator,
            I::Item: Clone,
        {
            type Item = (I::Item, J::Item);

            fn next(&mut self) -> Option<(I::Item, J::Item)> {
                let elt_b = match self.b.next() {
                    None => {
                        self.b = self.b_orig.clone();
                        match self.b.next() {
                            None => return None,
                            Some(x) => {
                                self.a_cur = self.a.next();
                                x
                            }
                        }
                    }
                    Some(x) => x,
                };
                match self.a_cur {
                    None => None,
                    Some(ref a) => Some((a.clone(), elt_b)),
                }
            }

            fn size_hint(&self) -> (usize, Option<usize>) {
                let has_cur = self.a_cur.is_some() as usize;
                // Not ExactSizeIterator because size may be larger than usize
                let (b_min, b_max) = self.b.size_hint();

                // Compute a * b_orig + b for both lower and upper bound
                super::size_hint::add(
                    super::size_hint::mul(self.a.size_hint(), self.b_orig.size_hint()),
                    (b_min * has_cur, b_max.map(move |x| x * has_cur)),
                )
            }

            fn fold<Acc, G>(mut self, mut accum: Acc, mut f: G) -> Acc
            where
                G: FnMut(Acc, Self::Item) -> Acc,
            {
                if let Some(mut a) = self.a_cur.take() {
                    let mut b = self.b;
                    loop {
                        accum = b.fold(accum, |acc, elt| f(acc, (a.clone(), elt)));

                        // we can only continue iterating a if we had a first element;
                        if let Some(next_a) = self.a.next() {
                            b = self.b_orig.clone();
                            a = next_a;
                        } else {
                            break;
                        }
                    }
                }
                accum
            }
        }
    }

    #[allow(missing_docs)]
    mod intersperse {
        use super::size_hint;
        use std::iter;

        #[derive(Debug, Clone)]
        #[must_use = "iterator adaptors are lazy and do nothing unless consumed"]
        pub struct Intersperse<I>
        where
            I: Iterator,
        {
            element: I::Item,
            iter: iter::Fuse<I>,
            peek: Option<I::Item>,
        }

        pub fn intersperse<I>(iter: I, elt: I::Item) -> Intersperse<I>
        where
            I: Iterator,
        {
            let mut iter = iter.fuse();
            Intersperse {
                peek: iter.next(),
                iter,
                element: elt,
            }
        }

        impl<I> Iterator for Intersperse<I>
        where
            I: Iterator,
            I::Item: Clone,
        {
            type Item = I::Item;
            #[inline]
            fn next(&mut self) -> Option<I::Item> {
                if self.peek.is_some() {
                    self.peek.take()
                } else {
                    self.peek = self.iter.next();
                    if self.peek.is_some() {
                        Some(self.element.clone())
                    } else {
                        None
                    }
                }
            }

            fn size_hint(&self) -> (usize, Option<usize>) {
                // 2 * SH + { 1 or 0 }
                let has_peek = self.peek.is_some() as usize;
                let sh = self.iter.size_hint();
                size_hint::add_scalar(size_hint::add(sh, sh), has_peek)
            }

            fn fold<B, F>(mut self, init: B, mut f: F) -> B
            where
                Self: Sized,
                F: FnMut(B, Self::Item) -> B,
            {
                let mut accum = init;

                if let Some(x) = self.peek.take() {
                    accum = f(accum, x);
                }

                let element = &self.element;

                self.iter.fold(accum, |accum, x| {
                    let accum = f(accum, element.clone());
                    f(accum, x)
                })
            }
        }
    }

    #[allow(missing_docs)]
    mod format_intersparse {
        use super::Seq;
        use std::fmt;

        pub fn format_intersparse<I, T>(iter: I, separator: T) -> String
        where
            I: Iterator,
            I::Item: fmt::Display,
            T: fmt::Display,
        {
            iter.map(|x| format!("{}", x))
                .intersperse(format!("{}", separator))
                .collect::<String>()
        }
    }

    mod size_hint {

        use std::cmp;
        use std::usize;

        pub type SizeHint = (usize, Option<usize>);

        #[inline]
        pub fn add(a: SizeHint, b: SizeHint) -> SizeHint {
            let min = a.0.saturating_add(b.0);
            let max = match (a.1, b.1) {
                (Some(x), Some(y)) => x.checked_add(y),
                _ => None,
            };

            (min, max)
        }

        #[inline]
        #[allow(dead_code)]
        pub fn add_scalar(sh: SizeHint, x: usize) -> SizeHint {
            let (mut low, mut hi) = sh;
            low = low.saturating_add(x);
            hi = hi.and_then(|elt| elt.checked_add(x));
            (low, hi)
        }

        #[inline]
        #[allow(dead_code)]
        pub fn sub_scalar(sh: SizeHint, x: usize) -> SizeHint {
            let (mut low, mut hi) = sh;
            low = low.saturating_sub(x);
            hi = hi.map(|elt| elt.saturating_sub(x));
            (low, hi)
        }

        #[inline]
        #[allow(dead_code)]
        pub fn mul(a: SizeHint, b: SizeHint) -> SizeHint {
            let low = a.0.saturating_mul(b.0);
            let hi = match (a.1, b.1) {
                (Some(x), Some(y)) => x.checked_mul(y),
                (Some(0), None) | (None, Some(0)) => Some(0),
                _ => None,
            };
            (low, hi)
        }

        #[inline]
        #[allow(dead_code)]
        pub fn mul_scalar(sh: SizeHint, x: usize) -> SizeHint {
            let (mut low, mut hi) = sh;
            low = low.saturating_mul(x);
            hi = hi.and_then(|elt| elt.checked_mul(x));
            (low, hi)
        }

        #[inline]
        #[allow(dead_code)]
        pub fn max(a: SizeHint, b: SizeHint) -> SizeHint {
            let (a_lower, a_upper) = a;
            let (b_lower, b_upper) = b;

            let lower = cmp::max(a_lower, b_lower);

            let upper = match (a_upper, b_upper) {
                (Some(x), Some(y)) => Some(cmp::max(x, y)),
                _ => None,
            };

            (lower, upper)
        }

        #[inline]
        #[allow(dead_code)]
        pub fn min(a: SizeHint, b: SizeHint) -> SizeHint {
            let (a_lower, a_upper) = a;
            let (b_lower, b_upper) = b;
            let lower = cmp::min(a_lower, b_lower);
            let upper = match (a_upper, b_upper) {
                (Some(u1), Some(u2)) => Some(cmp::min(u1, u2)),
                _ => a_upper.or(b_upper),
            };
            (lower, upper)
        }
    }
}
// }}}

fn main() {
    let mut buf = ngtio::Buffer::new();
    let h = buf.usize();
    let w = buf.usize();
    let grid = iter::repeat_with(|| buf.string().chars().collect::<Vec<_>>())
        .take(h)
        .collect::<Vec<_>>();

    let encode = |i: usize, j: usize| i * w + j;
    let alive = seq::cartesian_product(0..h, 0..w)
        .filter(|&(i, j)| grid[i][j] != '#')
        .collect::<Vec<_>>();

    let n = h * w;
    let mut mcf = mincostflow::MinCostFlowGraph::new(n + 2);
    let shift = 1_000_000_000;
    let s = n;
    let t = n + 1;
    for &(i, j) in &alive {
        if grid[i][j] == 'o' {
            mcf.add_edge(s, encode(i, j), 1, (i + j) as i64);
        }
        mcf.add_edge(encode(i, j), t, 1, shift - (i + j) as i64);
        if i != h - 1 && grid[i + 1][j] != '#' {
            mcf.add_edge(encode(i, j), encode(i + 1, j), std::i64::MAX, 0);
        }
        if j != w - 1 && grid[i][j + 1] != '#' {
            mcf.add_edge(encode(i, j), encode(i, j + 1), std::i64::MAX, 0);
        }
    }
    let (flow, cost) = mcf.flow(s, t, std::i64::MAX);
    let ans = flow * shift - cost;
    assert!(0 <= ans);
    println!("{}", ans);
}

//https://github.com/rust-lang-ja/ac-library-rs
pub mod internal_type_traits {
    use std::{
        fmt,
        iter::{Product, Sum},
        ops::{
            Add, AddAssign, BitAnd, BitAndAssign, BitOr, BitOrAssign, BitXor, BitXorAssign, Div,
            DivAssign, Mul, MulAssign, Not, Rem, RemAssign, Shl, ShlAssign, Shr, ShrAssign, Sub,
            SubAssign,
        },
    };

    // Skipped:
    //
    // - `is_signed_int_t<T>`   (probably won't be used directly in `modint.rs`)
    // - `is_unsigned_int_t<T>` (probably won't be used directly in `modint.rs`)
    // - `to_unsigned_t<T>`     (not used in `fenwicktree.rs`)

    /// Corresponds to `std::is_integral` in C++.
    // We will remove unnecessary bounds later.
    //
    // Maybe we should rename this to `PrimitiveInteger` or something, as it probably won't be used in the
    // same way as the original ACL.
    pub trait Integral:
        'static
        + Send
        + Sync
        + Copy
        + Ord
        + Not<Output = Self>
        + Add<Output = Self>
        + Sub<Output = Self>
        + Mul<Output = Self>
        + Div<Output = Self>
        + Rem<Output = Self>
        + AddAssign
        + SubAssign
        + MulAssign
        + DivAssign
        + RemAssign
        + Sum
        + Product
        + BitOr<Output = Self>
        + BitAnd<Output = Self>
        + BitXor<Output = Self>
        + BitOrAssign
        + BitAndAssign
        + BitXorAssign
        + Shl<Output = Self>
        + Shr<Output = Self>
        + ShlAssign
        + ShrAssign
        + fmt::Display
        + fmt::Debug
        + fmt::Binary
        + fmt::Octal
        + Zero
        + One
        + BoundedBelow
        + BoundedAbove
    {
    }

    /// Class that has additive identity element
    pub trait Zero {
        /// The additive identity element
        fn zero() -> Self;
    }

    /// Class that has multiplicative identity element
    pub trait One {
        /// The multiplicative identity element
        fn one() -> Self;
    }

    pub trait BoundedBelow {
        fn min_value() -> Self;
    }

    pub trait BoundedAbove {
        fn max_value() -> Self;
    }

    macro_rules! impl_integral {
    ($($ty:ty),*) => {
        $(
            impl Zero for $ty {
                #[inline]
                fn zero() -> Self {
                    0
                }
            }

            impl One for $ty {
                #[inline]
                fn one() -> Self {
                    1
                }
            }

            impl BoundedBelow for $ty {
                #[inline]
                fn min_value() -> Self {
                    Self::min_value()
                }
            }

            impl BoundedAbove for $ty {
                #[inline]
                fn max_value() -> Self {
                    Self::max_value()
                }
            }

            impl Integral for $ty {}
        )*
    };
}

    impl_integral!(i8, i16, i32, i64, i128, isize, u8, u16, u32, u64, u128, usize);
}
pub mod mincostflow {
    use crate::internal_type_traits::Integral;

    pub struct MinCostFlowEdge<T> {
        pub from: usize,
        pub to: usize,
        pub cap: T,
        pub flow: T,
        pub cost: T,
    }

    #[derive(Debug, Clone)]
    pub struct MinCostFlowGraph<T> {
        pos: Vec<(usize, usize)>,
        pub g: Vec<Vec<_Edge<T>>>,
        cost_sum: T,
    }

    impl<T> MinCostFlowGraph<T>
    where
        T: Integral + std::ops::Neg<Output = T>,
    {
        pub fn new(n: usize) -> Self {
            Self {
                pos: vec![],
                g: (0..n).map(|_| vec![]).collect(),
                cost_sum: T::zero(),
            }
        }

        pub fn get_edge(&self, i: usize) -> MinCostFlowEdge<T> {
            assert!(i < self.pos.len());
            let e = &self.g[self.pos[i].0][self.pos[i].1];
            let re = &self.g[e.to][e.rev];
            MinCostFlowEdge {
                from: self.pos[i].0,
                to: e.to,
                cap: e.cap + re.cap,
                flow: re.cap,
                cost: e.cost,
            }
        }

        pub fn edges(&self) -> Vec<MinCostFlowEdge<T>> {
            let m = self.pos.len();
            let mut result = vec![];
            for i in 0..m {
                result.push(self.get_edge(i));
            }
            result
        }

        pub fn add_edge(&mut self, from: usize, to: usize, cap: T, cost: T) -> usize {
            assert!(from < self.g.len());
            assert!(to < self.g.len());
            assert_ne!(from, to);
            assert!(cap >= T::zero());
            assert!(cost >= T::zero());

            self.pos.push((from, self.g[from].len()));
            self.cost_sum += cost;

            let rev = self.g[to].len();
            self.g[from].push(_Edge { to, rev, cap, cost });

            let rev = self.g[from].len() - 1;
            self.g[to].push(_Edge {
                to: from,
                rev,
                cap: T::zero(),
                cost: -cost,
            });

            self.pos.len() - 1
        }

        /// Returns (maximum flow, cost)
        pub fn flow(&mut self, source: usize, sink: usize, flow_limit: T) -> (T, T) {
            self.slope(source, sink, flow_limit).pop().unwrap()
        }

        pub fn slope(&mut self, source: usize, sink: usize, flow_limit: T) -> Vec<(T, T)> {
            let n = self.g.len();
            assert!(source < n);
            assert!(sink < n);
            assert_ne!(source, sink);

            let mut dual = vec![T::zero(); n];
            let mut prev_v = vec![0; n];
            let mut prev_e = vec![0; n];
            let mut flow = T::zero();
            let mut cost = T::zero();
            let mut prev_cost: Option<T> = None;
            let mut result = vec![(flow, cost)];
            while flow < flow_limit {
                if !self.refine_dual(source, sink, &mut dual, &mut prev_v, &mut prev_e) {
                    break;
                }

                let mut c = flow_limit - flow;
                let mut v = sink;
                while v != source {
                    c = std::cmp::min(c, self.g[prev_v[v]][prev_e[v]].cap);
                    v = prev_v[v];
                }

                let mut v = sink;
                while v != source {
                    self.g[prev_v[v]][prev_e[v]].cap -= c;
                    let rev = self.g[prev_v[v]][prev_e[v]].rev;
                    self.g[v][rev].cap += c;
                    v = prev_v[v];
                }

                let d = -dual[source];
                flow += c;
                cost += d * c;
                if prev_cost == Some(d) {
                    assert!(result.pop().is_some());
                }
                result.push((flow, cost));
                prev_cost = Some(cost);
            }
            result
        }

        fn refine_dual(
            &self,
            source: usize,
            sink: usize,
            dual: &mut [T],
            pv: &mut [usize],
            pe: &mut [usize],
        ) -> bool {
            let n = self.g.len();
            let mut dist = vec![self.cost_sum; n];
            let mut vis = vec![false; n];

            let mut que = std::collections::BinaryHeap::new();
            dist[source] = T::zero();
            que.push((std::cmp::Reverse(T::zero()), source));
            while let Some((_, v)) = que.pop() {
                if vis[v] {
                    continue;
                }
                vis[v] = true;
                if v == sink {
                    break;
                }

                for (i, e) in self.g[v].iter().enumerate() {
                    if vis[e.to] || e.cap == T::zero() {
                        continue;
                    }

                    let cost = e.cost - dual[e.to] + dual[v];
                    if dist[e.to] - dist[v] > cost {
                        dist[e.to] = dist[v] + cost;
                        pv[e.to] = v;
                        pe[e.to] = i;
                        que.push((std::cmp::Reverse(dist[e.to]), e.to));
                    }
                }
            }

            if !vis[sink] {
                return false;
            }

            for v in 0..n {
                if !vis[v] {
                    continue;
                }
                dual[v] -= dist[sink] - dist[v];
            }
            true
        }
    }

    #[derive(Debug, Clone)]
    pub struct _Edge<T> {
        to: usize,
        rev: usize,
        cap: T,
        cost: T,
    }

    #[cfg(test)]
    mod tests {
        use super::*;

        #[test]
        fn test_min_cost_flow() {
            let mut graph = MinCostFlowGraph::new(4);
            graph.add_edge(0, 1, 2, 1);
            graph.add_edge(0, 2, 1, 2);
            graph.add_edge(1, 2, 1, 1);
            graph.add_edge(1, 3, 1, 3);
            graph.add_edge(2, 3, 2, 1);
            let (flow, cost) = graph.flow(0, 3, 2);
            assert_eq!(flow, 2);
            assert_eq!(cost, 6);
        }
    }
}
use mincostflow::*;


Measured memory_bytes: 3084