#include <bits/stdc++.h>

using namespace std;
#define pb push_back
#define all(x) x.begin(), x.end()
#define sz(x) (int)x.size()
using ll = long long;
using pii = pair<int, int>;
using ull = unsigned long long;


const int mn = 55;

namespace Min_Cost_Max_Flow {
    const int INF = 0x3f3f3f3f;  // INF flow
    const int N = 2503;          //最大点数
    const int M = 50000;         //最大边数
    int S, T, cnt, from[N], g[N], flow;
    ll d[N];  // 这里的 flow 就是最大流量
    ll ans;   // 费用，即为答案
    struct edge {
        int from, to, nxt, v;
        ll c;
    } e[M];  // c 是价格 v 是流量
    void add(int u, int v, int w, ll c) {
        e[++cnt].from = u;
        e[cnt].to = v;
        e[cnt].nxt = g[u];
        g[u] = cnt;
        e[cnt].c = c;
        e[cnt].v = w;
    }

    void add_edge(int u, int v, int w, ll c) {
        //printf("add_edge %d %d %d %lld\n", u, v, w, c);
        add(u, v, w, c);
        add(v, u, 0, -c);
    }

    bool spfa() {
        fill_n(d, N, INF);
        d[S] = 0;
        memset(from, 0, sizeof(from));
        queue<int> q;
        q.push(S);
        while (!q.empty()) {
            int now = q.front();
            q.pop();
            for (int i = g[now]; i; i = e[i].nxt) {
                if (e[i].v && d[e[i].to] > d[now] + e[i].c) {
                    d[e[i].to] = d[now] + e[i].c;
                    from[e[i].to] = i;
                    q.push(e[i].to);
                }
            }
        }
        return (d[T] != INF);
        // 改为return(d[T]<=0)即为最小费用可行流
    }

    void mcf() {
        int x = INF;
        for (int i = from[T]; i; i = from[e[i].from]) x = min(x, e[i].v);
        flow += x;
        for (int i = from[T]; i; i = from[e[i].from]) {
            e[i].v -= x;
            e[i ^ 1].v += x;
            ans += e[i].c * x;
        }
    }

    void Initialize(int s, int t) {  //源点和汇点
        S = s;
        T = t;
        memset(g, 0, sizeof(g));
        memset(e, 0, sizeof(e));
        ans = flow = 0;
        cnt = 1;
    }

    void doit() {
        while (spfa()) mcf();
    }
}  // namespace Min_Cost_Max_Flow


int n, m;
char s[mn][mn];

int getid(int x, int y) {
    return (x - 1) * m + y;
}

int vis[mn][mn];
int to_end[mn][mn];

int head_count = 0;

void calc(int x, int y) {
    struct node {
        int x, y, t;

        bool operator<(const node &p) const {
            return t > p.t;
        }
    };
    memset(vis, 0, sizeof vis);
    queue<node> q;
    q.push({x, y, 0});
    vector<node> v;
    while (!q.empty()) {
        node u = q.front();
        q.pop();
        //printf("%d %d\n", u.x, u.y);
        v.push_back(u);
        if (u.x < n) {
            node nxt = {u.x + 1, u.y, u.t + 1};
            if (!(vis[nxt.x][nxt.y] || s[nxt.x][nxt.y] == '#')) {
                vis[nxt.x][nxt.y] = 1;
                q.push(nxt);
            }
        }
        if (u.y < m) {
            node nxt = {u.x, u.y + 1, u.t + 1};
            if (vis[nxt.x][nxt.y] || s[nxt.x][nxt.y] == '#') continue;
            vis[nxt.x][nxt.y] = 1;
            q.push(nxt);
        }
    }
    sort(begin(v), end(v));

    using namespace Min_Cost_Max_Flow;
    for (int i = 0; i < v.size() && i < head_count; i++) {
        node &p = v[i];
        if (p.t == 0) break;
        //printf("%d %d -> %d %d : %d\n", x, y, p.x, p.y, p.t);
        add_edge(getid(x, y), getid(p.x, p.y), 1, -p.t);
        if (!to_end[p.x][p.y]) {
            to_end[p.x][p.y] = 1;
            add_edge(getid(p.x, p.y), n * m + 1, 1, 0);
        }
    }
    if (!to_end[x][y]) {
        to_end[x][y] = 1;
        add_edge(getid(x, y), n * m + 1, 1, 0);
    }
}

int main() {
    //cin.sync_with_stdio(0);
#ifdef trote
    freopen("../1.txt", "r", stdin);
    //freopen("../2.txt", "w", stdout);
    auto bg = clock();
#endif

    using namespace Min_Cost_Max_Flow;
    scanf("%d%d", &n, &m);
    Initialize(0, n * m + 1);
    for (int i = 1; i <= n; i++) {
        scanf("%s", s[i] + 1);
    }
    for (int i = 1; i <= n; i++) {
        for (int j = 1; j <= m; j++) {
            if (s[i][j] == 'o') {
                add_edge(0, getid(i, j), 1, 0);
                head_count++;
            }
        }
    }
    for (int i = 1; i <= n; i++) {
        for (int j = 1; j <= m; j++) {
            if (s[i][j] == 'o') {
                calc(i, j);
            }
        }
    }
    doit();
    printf("%lld\n", -ans);
}

Measured memory_bytes: 5056