#include <bits/stdc++.h>

const int MAX_RC = 55;
const int MAX_S = 105;
const int MIN = -1000000000;
char g[MAX_RC][MAX_RC];
int dr[2] = {1, 0};
int dc[2] = {0, 1};
int R, C;

using namespace std;

const int INF = numeric_limits<int>::max()/2;
const int NODES = MAX_RC*MAX_RC+5;

struct edge {
  int u, v, cap, cst, rev;
};
vector<edge> E;
vector<int> al[NODES];

void add_edge(int u, int v, int cap, int cst) {
  int eid = E.size();
  al[u].push_back(eid);
  E.push_back(edge({u, v, cap, cst, eid+1}));
  al[v].push_back(eid+1);
  E.push_back(edge({v, u, 0, -cst, eid}));
}


int inQ[NODES], parent[NODES], D[NODES];

struct MCMF { // O(max_flow * augment)
  void augment_spfa(int s) {  // Fills parent and D.
    fill(parent, parent+NODES, -1);
    fill(D, D+NODES, INF);
    fill(inQ, inQ+NODES, 0);
    D[s] = 0; inQ[s] = 1;
    queue<int> q; q.push(s);
    while (!q.empty()) { // Loops forever on negative cycle.
      int at = q.front(); q.pop();
      inQ[at] = 0;
      for (int e : al[at]) if (E[e].cap) {
        int c = E[e].v, w = E[e].cst;
        if (D[at] + w < D[c]) {
          D[c] = D[at] + w;
          parent[c] = e;
          if (!inQ[c]) { q.push(c); inQ[c] = 1; }
        }
      }
    }
  }
  // Dijkstras can be worth it if SPFA is getting rekt by non-random input
  vector<int> pi;
  void augment_dijks(int s) {
    if (pi.size() == 0) { // Get rid of negative edge costs
      pi.assign(NODES+1, 0); // For dijkstra potentials. N+1 for special node
      // vector<int> tmp(N); // Can remove the rest of this for no-neg weights input
      // for (int i = 0; i < N; ++i) tmp[i] = i;
      // als.push_back(tmp); costs.push_back(vector<int>(N)); // Special node
      // for (int i = 0; i < N; ++i) // Bellman-ford V-1 iterations
      //  for (int u = 0; u <= N; ++u) for (int c : als[u]) if (u >= N || caps[u][c]) {
      //    pi[c] = min(pi[c], costs[u][c] + pi[u]);
      //  }
      // als.pop_back(); costs.pop_back();
    }
    fill(parent, parent+NODES, -1);
    fill(D, D+NODES, INF);
    map<int, queue<pair<int, int>>> pq;

    pq[0].emplace(s, -1);
    while (pq.size()) {
      // assert(pq.size() < 5);
      int at, paredge, d;
      auto& kv = *pq.begin();
      d = kv.first;
      tie(at, paredge) = kv.second.front();
      kv.second.pop();
      if (kv.second.empty()) {
        pq.erase(kv.first);
      }
      if (d > D[at]) continue;
      parent[at] = paredge;
      for (int e : al[at]) if (E[e].cap) {
        int c = E[e].v, w = E[e].cst;
        w += pi[at] - pi[c];
        if (w+d < D[c]) {
          D[c] = w+d;
          pq[w+d].emplace(c, e);
        }
      }
    }
    for (int i = 0; i < NODES; ++i) if (parent[i] != -1)
      pi[i] += D[i]; // Maintain no neg cost edges
  }
  pair<int, int> run(int s, int t) {
    int flow = 0; int fcost = 0;
    augment_spfa(s);
    while (parent[t] != -1) { // Keep finding augmenting paths.
      int bottle = INF;
      for (int at = t; at != s; at = E[parent[at]].u) { // Find bottleneck.
        bottle = min(bottle, E[parent[at]].cap);
      }
      flow += bottle;
      for (int at = t; at != s; at = E[parent[at]].u) { // Push the flow.
        edge& e = E[parent[at]];
        edge& re = E[e.rev];
        fcost += bottle*e.cst;
        e.cap -= bottle;
        re.cap += bottle;
      }
      augment_spfa(s);
    }
    return {fcost, flow};
  }
};

vector<vector<int>> cost, adj;

int main() {
  scanf(" %d %d ", &R, &C);
  cost.resize(R*C+2, std::vector<int>(R*C+2, 0));
  adj.resize(R*C+2, std::vector<int>(R*C+2, 0));
  for (int r = 0; r < R; ++r) {
    for (int c = 0; c < C; ++c) {
      scanf("%c", &g[r][c]);
      if (g[r][c] == 'o') {
        add_edge(R*C, C*r+c, 1, 0);
      }
      add_edge(C*r + c, R*C+1, 1, 0);
    }
    scanf(" ");
  }
  for (int r = 0; r < R; ++r) {
    for (int c = 0; c < C; ++c) {
      if (g[r][c] == '#') continue;
      for (int i = 0; i < 2; ++i) {
        int nr = r + dr[i];
        int nc = c + dc[i];
        if (nr < 0 || nr >= R || nc < 0 || nc >= C) continue;
        if (g[nr][nc] == '#') continue;
        add_edge(C*r + c, C*nr + nc, 1000000000, -1);
      }
    }
  }

  MCMF mm;
  auto out = mm.run(R*C, R*C+1);
  printf("%d\n", -out.first);
}


Measured memory_bytes: 53136