#include <bits/stdc++.h>
using namespace std;
#ifdef tabr
#include "library/debug.cpp"
#else
#define debug(...)
#endif

template <typename T, typename C>
struct mcmf {
    T eps = (T)1e-9;

    struct edge {
        int from;
        int to;
        T c;
        T f;
        C cost;
    };

    vector<vector<int>> g;
    vector<edge> edges;
    vector<C> d;
    vector<int> q;
    vector<bool> in_queue;
    vector<int> pe;
    int n;
    int s, t;
    T flow;
    C cost;

    mcmf(int _n, int _s, int _t) : n(_n), s(_s), t(_t) {
        g.resize(n);
        d.resize(n);
        in_queue.resize(n);
        pe.resize(n);
        flow = 0;
        cost = 0;
    }

    void clear_flow() {
        for (const edge &e : edges) {
            e.f = 0;
        }
        flow = 0;
    }

    void add(int from, int to, T forward_cap, T backward_cap = 0, C cost = 0) {
        g[from].push_back((int)edges.size());
        edges.push_back({from, to, forward_cap, 0, cost});
        g[to].push_back((int)edges.size());
        edges.push_back({to, from, backward_cap, 0, -cost});
    }

    bool bfs() {
        fill(d.begin(), d.end(), numeric_limits<C>::max());
        q.clear();
        q.push_back(s);
        d[s] = 0;
        in_queue[s] = true;
        int beg = 0;
        bool found = false;
        while (beg < (int)q.size()) {
            int i = q[beg++];
            if (i == t) {
                found = true;
            }
            in_queue[i] = false;
            for (int id : g[i]) {
                edge &e = edges[id];
                if (e.c - e.f > eps && d[i] + e.cost < d[e.to]) {
                    d[e.to] = d[i] + e.cost;
                    pe[e.to] = id;
                    if (!in_queue[e.to]) {
                        q.push_back(e.to);
                        in_queue[e.to] = true;
                    }
                }
            }
        }
        if (found) {
            T push = numeric_limits<T>::max();
            int v = t;
            while (v != s) {
                edge &e = edges[pe[v]];
                push = min(push, e.c - e.f);
                v = e.from;
            }
            v = t;
            while (v != s) {
                edge &e = edges[pe[v]];
                e.f += push;
                edge &back = edges[pe[v] ^ 1];
                back.f -= push;
                v = e.from;
            }
            flow += push;
            cost += push * d[t];
        }
        return found;
    }

    pair<T, C> max_flow_min_cost() {
        while (bfs()) 0;
        return {flow, cost};
    }
};

int main() {
    ios::sync_with_stdio(false);
    cin.tie(0);
    int h, w;
    cin >> h >> w;
    vector<string> s(h);
    mcmf<int, int> f(h * w + 2, h * w, h * w + 1);
    for (int i = 0; i < h; i++) {
        cin >> s[i];
    }
    for (int i = 0; i < h; i++) {
        for (int j = 0; j < w; j++) {
            if (s[i][j] == 'o') {
                f.add(h * w, i * w + j, 1, 0, 0);
            }
            if (s[i][j] != '#') {
                f.add(i * w + j, h * w + 1, 1, 0, 0);
                if (i != h - 1 && s[i + 1][j] != '#') {
                    f.add(i * w + j, (i + 1) * w + j, 200, 0, -1);
                }
                if (j != w - 1 && s[i][j + 1] != '#') {
                    f.add(i * w + j, i * w + j + 1, 200, 0, -1);
                }
            }
        }
    }
    cout << -f.max_flow_min_cost().second << '\n';
    return 0;
}

Measured memory_bytes: 4020