#include <bits/stdc++.h>
using namespace std;

#define Gene template< class
#define Rics printer& operator,
Gene c> struct rge{c b, e;};
Gene c> rge<c> range(c i, c j){ return {i, j};}
struct printer{
    ~printer(){cerr<<endl;}
    Gene c >Rics(c x){ cerr<<boolalpha<<x; return *this;}
    Rics(string x){cerr<<x;return *this;}
    Gene c, class d >Rics(pair<c, d> x){ return *this,"(",x.first,", ",x.second,")";}
    Gene ... d, Gene ...> class c >Rics(c<d...> x){ return *this, range(begin(x), end(x));}
    Gene c >Rics(rge<c> x){
        *this,"["; for(auto it = x.b; it != x.e; ++it)
            *this,(it==x.b?"":", "),*it; return *this,"]";}
};
#define debug() cerr<<"LINE "<<__LINE__<<" >> ", printer()
#define dbg(x) "[",#x,": ",(x),"] "
mt19937 rng(chrono::steady_clock::now().time_since_epoch().count());
int my_rand(int l, int r) {
    return uniform_int_distribution<int>(l, r) (rng);
}

namespace mcmf{
    const int MAX = 101000; const int INF = 1e9;
    int cap[MAX], flow[MAX], cost[MAX], dis[MAX];
    int n, m, s, t, Q[MAX*100], adj[MAX], link[MAX], last[MAX],
    from[MAX], visited[MAX];
    void init(int nodes, int source, int sink){
      m = 0, n = nodes, s = source, t = sink;
      for (int i = 0; i <= n; i++) last[i] = -1;
    }
    void addEdge(int u, int v, long long c, long long w){
      adj[m] = v, cap[m] = c, flow[m] = 0, cost[m] = +w,
      link[m] = last[u], last[u] = m++;
      adj[m] = u, cap[m] = 0, flow[m] = 0,
      cost[m] = -w, link[m] = last[v], last[v] = m++;
    }
    bool spfa() {
      int i, j, x, f = 0, l = 0;
      for (i = 0; i <= n; i++) visited[i] = 0, dis[i] = INF;
      dis[s] = 0, Q[l++] = s;
      while (f < l) {
        i = Q[f++];
        for (j = last[i]; j != -1; j = link[j]) {
          if (flow[j] < cap[j]) {
          x = adj[j];
            if (dis[x] > dis[i] + cost[j]) {
              dis[x] = dis[i] + cost[j], from[x] = j;
              if (!visited[x]) {
                  visited[x] = 1;
                  if (f && rand() & 7) Q[--f] = x;
                  else Q[l++] = x;
              }
            }
          }
        }
        visited[i] = 0;
      }
      return (dis[t] != INF);
    }
    pair <int, int> solve() {
        int i, j;
        int mincost = 0, maxflow = 0;
        while (spfa()) {
          int aug = INF;
          for(i=t,j=from[i];i!=s;i=adj[j^1],j = from[i]){
                aug = min(aug, cap[j] - flow[j]);
            }
            for(i=t,j=from[i];i!=s;i=adj[j^1],j=from[i]){
                flow[j] += aug, flow[j ^ 1] -= aug;
            }
            maxflow += aug, mincost += aug * dis[t];
        }
        return make_pair(mincost, maxflow);
    }
}


const int N = 55;

int dx[] = {0, +1};
int dy[] = {+1, 0};

int n, m;
string grid[N];
bool vis[N][N];
int idx[N][N], idx2[N][N];

void dfs(int x, int y) {
    vis[x][y] = true;
    for(int k = 0; k < 2; k++) {
        int xx = x+dx[k], yy = y+dy[k];
        if(xx >= 0 && xx < n && yy >= 0 && yy < m && vis[xx][yy] == false && grid[xx][yy] != '#') {
            dfs(xx, yy);
        }
    }
}

int main() {
//    freopen("in.txt", "r", stdin);
    ios::sync_with_stdio(0);
    cin.tie(0);

    cin >> n >> m;
    for(int i = 0; i < n; i++) cin >> grid[i];

    int id = 0;
    for(int i = 0; i < n; i++) {
        for(int j = 0; j < m; j++) {
            if(grid[i][j] == 'o') {
                idx[i][j] = ++id;
            }
        }
    }
    int source = 0, sink = id+n*m+1;
    mcmf::init(id+n*m+2, source, sink);
    for(int i = 1; i <= id; i++) mcmf::addEdge(source, i, +1, 0);

    for(int i = 0; i < n; i++) {
        for(int j = 0; j < m; j++) {
            idx2[i][j] = ++id;
            mcmf::addEdge(idx2[i][j], sink, +1, 0);
        }
    }

    for(int i = 0; i < n; i++) {
        for(int j = 0; j < m; j++) {
            if(grid[i][j] == 'o') {
                memset(vis, 0, sizeof vis);
                dfs(i, j);
                vector<tuple<int,int,int>> visited;
                for(int x = 0; x < n; x++) {
                    for(int y = 0; y < m; y++) {
                        if(vis[x][y]) {
                            visited.push_back(make_tuple(abs(x-i)+abs(y-j), x, y));
                        }
                    }
                }
                sort(visited.rbegin(), visited.rend());
                while(visited.size() > 100) visited.pop_back();
                for(auto t : visited) {
                    int x = get<1>(t), y = get<2>(t), z = get<0>(t);
                    mcmf::addEdge(idx[i][j], idx2[x][y], +1, -z);
                }
            }
        }
    }
    auto res = mcmf::solve();
    cout << -res.first << endl;
}





Measured memory_bytes: 4260