#include <bits/stdc++.h>
#pragma GCC optimize("Ofast")
#pragma GCC target("avx,avx2,fma")
using namespace std;
typedef long long ll;
#define pb push_back
#define mii map<int, int>
#define mll map<ll, ll>
#define pii pair<int, int>
#define pll pair<ll, ll>
#define vi vector<int>
#define vd vector<double>
#define vll vector<ll>
#define fi first
#define se second
#define si set<int>
#define sll set<ll>
#define spii set<pii>
#define vs vector<string>
#define vpii vector<pair<int, int>>
#define vpll vector<pair<long long, long long>>
#define vvi vector<vector<int>>
#define vvpii vector<vector<pii>>
#define vb vector<bool>
#define vvb vector<vb>
#define mp make_pair
#define vvll vector<vll>
#define vsi vector<si>
#define rep(i, n) for (int i = 0; i < (n); i++)
#define all(x) (x).begin(), (x).end()
#define rall(x) (x).rbegin(), (x).rend()
#define MANX MAXN
#define itn int
#define in(x)                                                                  \\
  ;                                                                            \\
  {                                                                            \\
    for (auto &to : x)                                                         \\
      cin >> to;                                                               \\
  }
#define out(x)                                                                 \\
  ;                                                                            \\
  {                                                                            \\
    for (auto &to : x)                                                         \\
      cout << to << " ";                                                       \\
    cout << '\\n';                                                              \\
  }
const ll infl = 4e18;
const ll INFLL = 1e18;
const int MAXN = 1e6 + 100;
const ll INF = 1e9;
const int INF_new = 100 * 50 * 50 * 50;
const ll mod1 = 1e9 + 7;
const ll mod2 = 2e9 + 11;
int nn, mm;
int n, m;
ll a[101][50 * 50 + 2];
#define rep(i, a, b) for (int i = (a); i <= (b); i++)
ll hungarian() {  // Return the matching job->worker but in 1-indexing -> job[1]
                  // = 2
  vi mtch(m + 1); // mtch[i] = job assigned to person i in current matching
  vll u(n + 1);
  vll v(m + 1);
  vi way(m + 1);
  vi pre(m + 1);
  rep(i, 1, n) { // Augment from i by finding an increasing chain - Kuhn
    vll dist(m + 1, infl);
    vb vis(m + 1, false);
    int cur_per = 0;
    mtch[cur_per] = i;
    while (mtch[cur_per]) { // While there is an not an unsaturated person
      int cur_job = mtch[cur_per];
      vis[cur_per] = true;
      ll delta = infl;
      int nxt_per;
      rep(j, 1, m) {
        if (!vis[j]) {
          ll val = a[cur_job][j] - u[cur_job] - v[j];
          if (val < dist[j]) {
            dist[j] = val;
            way[j] = cur_per;
          }
          if (dist[j] < delta) {
            delta = dist[j];
            nxt_per = j;
          }
        }
      }
      rep(j, 0, m) {
        if (vis[j]) {
          u[mtch[j]] += delta;
          v[j] -= delta;
        } else {
          dist[j] -= delta;
        }
      }
      cur_per = nxt_per;
    }
    while (cur_per) { // Flip the matching
      int prev_per = way[cur_per];
      mtch[cur_per] = mtch[prev_per];
      cur_per = prev_per;
    }
  }
  return -v[0];
}
int k = 0;
vector<string> s;
int curr = 1;
vector<int> x = {1, 0};
vector<int> y = {0, 1};
void dfs(int i, int j, int ok) {
  // cout<<i<<" "<<j<<" "<<nn*mm<<" "<<i*mm+j<<" "<<curr<<'\\n';
  a[curr][i * mm + j + 1] = -ok;
  for (int f = 0; f < 2; f++) {
    if (i + x[f] < nn && j + y[f] < mm && s[i + x[f]][j + y[f]] != '#') {
      dfs(i + x[f], j + y[f], ok + 1);
    }
  }
}

void solve() {
  cin >> nn >> mm;
  s = vector<string>(nn);
  for (int i = 0; i < nn; i++)
    cin >> s[i];
  for (int i = 0; i < nn; i++) {
    for (int j = 0; j < mm; j++)
      k += s[i][j] == 'o';
  }
  for (int i = 0; i <= k; i++) {
    for (int f = 0; f <= nn * mm; f++)
      a[i][f] = INF;
  }
  for (int i = 0; i < nn; i++) {
    for (int j = 0; j < mm; j++) {
      if (s[i][j] != 'o')
        continue;
      dfs(i, j, 0);
      curr++;
    }
  }
  n = k;
  m = nn * mm;
  cout << -hungarian() << '\\n';
}

int main() {
  ios_base::sync_with_stdio(0);
  cin.tie(0);
#ifdef Mip182
  freopen("a.in", "r", stdin);
#endif
  int _t;
  _t = 1;
  //   cin>>_t;
  while (_t--)
    solve();
  // n=1 ?
  // recursion - matrix exponential
  // linear algebra - just a joke
  // check ios_base, MAXN, mod1 before submit
  // if debug more than 15 minutes - write stress
  // compression
}

#include <bits/stdc++.h>
#pragma GCC optimize("Ofast")
#pragma GCC target("avx,avx2,fma")
using namespace std;
typedef long long ll;
#define pb push_back
#define mii map<int, int>
#define mll map<ll, ll>
#define pii pair<int, int>
#define pll pair<ll, ll>
#define vi vector<int>
#define vd vector<double>
#define vll vector<ll>
#define fi first
#define se second
#define si set<int>
#define sll set<ll>
#define spii set<pii>
#define vs vector<string>
#define vpii vector<pair<int, int>>
#define vpll vector<pair<long long, long long>>
#define vvi vector<vector<int>>
#define vvpii vector<vector<pii>>
#define vb vector<bool>
#define vvb vector<vb>
#define mp make_pair
#define vvll vector<vll>
#define vsi vector<si>
#define rep(i, n) for (int i = 0; i < (n); i++)
#define all(x) (x).begin(), (x).end()
#define rall(x) (x).rbegin(), (x).rend()
#define MANX MAXN
#define itn int
#define in(x)                                                                  \\
  ;                                                                            \\
  {                                                                            \\
    for (auto &to : x)                                                         \\
      cin >> to;                                                               \\
  }
#define out(x)                                                                 \\
  ;                                                                            \\
  {                                                                            \\
    for (auto &to : x)                                                         \\
      cout << to << " ";                                                       \\
    cout << '\\n';                                                              \\
  }
const ll infl = 4e18;
const ll INFLL = 1e18;
const int MAXN = 1e6 + 100;
const ll INF = 1e9;
const ll mod1 = 1e9 + 7;
const ll mod2 = 2e9 + 11;
int nn, mm;
int n, m;
ll a[101][50 * 50 + 2];
#define rep(i, a, b) for (int i = (a); i <= (b); i++)
ll hungarian() {  // Return the matching job->worker but in 1-indexing -> job[1]
                  // = 2
  vi mtch(m + 1); // mtch[i] = job assigned to person i in current matching
  vll u(n + 1);
  vll v(m + 1);
  vi way(m + 1);
  vi pre(m + 1);
  rep(i, 1, n) { // Augment from i by finding an increasing chain - Kuhn
    vll dist(m + 1, INFLL);
    vb vis(m + 1, false);
    int cur_per = 0;
    mtch[cur_per] = i;
    while (mtch[cur_per]) { // While there is an not an unsaturated person
      int cur_job = mtch[cur_per];
      vis[cur_per] = true;
      ll delta = infl;
      int nxt_per;
      rep(j, 1, m) {
        if (!vis[j]) {
          ll val = a[cur_job][j] - u[cur_job] - v[j];
          if (val < dist[j]) {
            dist[j] = val;
            way[j] = cur_per;
          }
          if (dist[j] < delta) {
            delta = dist[j];
            nxt_per = j;
          }
        }
      }
      rep(j, 0, m) {
        if (vis[j]) {
          u[mtch[j]] += delta;
          v[j] -= delta;
        } else {
          dist[j] -= delta;
        }
      }
      cur_per = nxt_per;
    }
    while (cur_per) { // Flip the matching
      int prev_per = way[cur_per];
      mtch[cur_per] = mtch[prev_per];
      cur_per = prev_per;
    }
  }
  return -v[0];
}
int k = 0;
vector<string> s;
int curr = 1;
vector<int> x = {1, 0};
vector<int> y = {0, 1};
vector<vector<bool>> used;
void dfs(int i, int j, int ok) {
  // cout<<i<<" "<<j<<" "<<nn*mm<<" "<<i*mm+j<<" "<<curr<<'\\n';
  a[curr][i * mm + j + 1] = -ok;
  used[i][j] = true;
  for (int f = 0; f < 2; f++) {
    if (i + x[f] < nn && j + y[f] < mm && s[i + x[f]][j + y[f]] != '#' &&
        !used[i + x[f]][j + y[f]]) {
      dfs(i + x[f], j + y[f], ok + 1);
    }
  }
}
void bfs(int i, int j) {
  queue<pii> q;
  q.push({i, j});
  a[curr][i * mm + j + 1] = 0;
  while (!q.empty()) {
    int xx = q.front().fi, yy = q.front().se;
    q.pop();
    for (int f = 0; f < 2; f++) {
      if (xx + x[f] < nn && yy + y[f] < mm && s[xx + x[f]][yy + y[f]] != '#' &&
          a[curr][(xx + x[f]) * mm + yy + y[f] + 1] == INF) {
        a[curr][(xx + x[f]) * mm + yy + y[f] + 1] =
            a[curr][xx * mm + yy + 1] - 1;
        // cout<<a[curr][xx*m+yy]-1<<'\\n';
        q.push({xx + x[f], yy + y[f]});
      }
    }
  }
}

void solve() {
  cin >> nn >> mm;
  //    nn = 50;
  //    mm = 50;
  s = vector<string>(nn);
  for (int i = 0; i < nn; i++)
    cin >> s[i];
  for (int i = 0; i < nn; i++) {
    for (int j = 0; j < mm; j++)
      k += s[i][j] == 'o';
  }
  // cout<<k<<'\\n';
  for (int i = 0; i <= k; i++) {
    for (int f = 0; f <= nn * mm; f++)
      a[i][f] = INF;
  }
  for (int i = 0; i < nn; i++) {
    for (int j = 0; j < mm; j++) {
      if (s[i][j] != 'o')
        continue;
      bfs(i, j);
      curr++;
    }
  }
  // cout<<"ahha\\n";
  n = k;
  m = nn * mm;
  cout << -hungarian() << '\\n';
}

int main() {
  ios_base::sync_with_stdio(0);
  cin.tie(0);
#ifdef Mip182
  freopen("a.in", "r", stdin);
#endif
  int _t;
  _t = 1;
  //   cin>>_t;
  while (_t--)
    solve();
  // n=1 ?
  // recursion - matrix exponential
  // linear algebra - just a joke
  // check ios_base, MAXN, mod1 before submit
  // if debug more than 15 minutes - write stress
  // compression
}


#include <bits/stdc++.h>

#define rep(i, x, y) for (int i = x, i##end = y; i <= i##end; ++i)
#define _rep(i, x, y) for (int i = x, i##end = y; i >= i##end; --i)
#define ll long long
#define pk push_back
#define N 100005
typedef std::pair<int, int> pii;
int s, t;
int cnt = 1, head[N], to[N], flow[N], cost[N], nxt[N];
inline void add(int u, int v, int w, int c) {
  to[++cnt] = v, flow[cnt] = w, cost[cnt] = c, nxt[cnt] = head[u],
  head[u] = cnt;
  to[++cnt] = u, flow[cnt] = 0, cost[cnt] = -c, nxt[cnt] = head[v],
  head[v] = cnt;
}
bool vis[N];
int pre[N], dep[N];
inline bool spfa(int s, int t) {
  memset(vis, 0, sizeof(vis));
  memset(pre, -1, sizeof(pre));
  memset(dep, 128, sizeof(dep));
  std::queue<int> q;
  q.push(s), dep[s] = 0, vis[s] = 1;
  int inf = dep[0];
  while (!q.empty()) {
    int u = q.front();
    q.pop();
    vis[u] = 0;
    for (int i = head[u]; i; i = nxt[i]) {
      if (flow[i] && dep[to[i]] < dep[u] + cost[i]) {
        dep[to[i]] = dep[u] + cost[i], pre[to[i]] = i;
        if (!vis[to[i]])
          vis[to[i]] = 1, q.push(to[i]);
      }
    }
  }
  return dep[t] != inf;
}
inline std::pair<int, int> mcmf(int s, int t) {
  std::pair<int, int> ret(0, 0);
  while (spfa(s, t)) {
    int mi = 2e9;
    for (int i = t; i != s; i = to[pre[i] ^ 1])
      mi = std::min(mi, flow[pre[i]]);
    for (int i = t; i != s; i = to[pre[i] ^ 1])
      flow[pre[i]] -= mi, flow[pre[i] ^ 1] += mi;
    ret.first += mi, ret.second += dep[t] * mi;
  }
  return ret;
}
int n, m;
char S[105][105];
inline int id(int x, int y) { return (x - 1) * m + y; }
int main() {
  std::ios::sync_with_stdio(0), std::cin.tie(0), std::cout.tie(0);
  std::cin >> n >> m, s = n * m, t = s + 1;
  rep(i, 1, n) std::cin >> S[i] + 1;
  rep(i, 1, n) rep(j, 1, m) if (S[i][j] != '#') {
    if (S[i][j] == 'o')
      add(s, id(i, j), 1, 0);
    if (i < n && S[i + 1][j] != '#')
      add(id(i, j), id(i + 1, j), 2e9, 1);
    if (j < m && S[i][j + 1] != '#')
      add(id(i, j), id(i, j + 1), 2e9, 1);
    add(id(i, j), t, 1, 0);
  }
  std::cout << mcmf(s, t).second << '\\n';
  return 0;
}

#include <bits/stdc++.h>

#define rep(i, x, y) for (int i = x, i##end = y; i <= i##end; ++i)
#define _rep(i, x, y) for (int i = x, i##end = y; i >= i##end; --i)
#define ll long long
#define pk push_back
#define N 100005
typedef std::pair<int, int> pii;
int s, t;
int cnt = 1, head[N], to[N], flow[N], cost[N], nxt[N];
inline void add(int u, int v, int w, int c) {
  to[++cnt] = v, flow[cnt] = w, cost[cnt] = c, nxt[cnt] = head[u],
  head[u] = cnt;
  to[++cnt] = u, flow[cnt] = 0, cost[cnt] = -c, nxt[cnt] = head[v],
  head[v] = cnt;
}
bool vis[N];
int pre[N], dep[N];
inline bool spfa(int s, int t) {
  memset(vis, 0, sizeof(vis));
  memset(pre, -1, sizeof(pre));
  memset(dep, 128, sizeof(dep));
  std::queue<int> q;
  q.push(s), dep[s] = 0, vis[s] = 1;
  int inf = dep[0];
  while (!q.empty()) {
    int u = q.front();
    q.pop();
    vis[u] = 0;
    for (int i = head[u]; i; i = nxt[i]) {
      if (flow[i] && dep[to[i]] < dep[u] + cost[i]) {
        dep[to[i]] = dep[u] + cost[i], pre[to[i]] = i;
        if (!vis[to[i]])
          vis[to[i]] = 1, q.push(to[i]);
      }
    }
  }
  return dep[t] != inf;
}
inline std::pair<int, int> mcmf(int s, int t) {
  std::pair<int, int> ret(0, 0);
  while (spfa(s, t)) {
    int mi = 2e9;
    for (int i = t; i != s; i = to[pre[i] ^ 1])
      mi = std::min(mi, flow[pre[i]]);
    for (int i = t; i != s; i = to[pre[i] ^ 1])
      flow[pre[i]] -= mi, flow[pre[i] ^ 1] += mi;
    ret.first += mi, ret.second += dep[t] * mi;
  }
  return ret;
}
int n, m;
char S[105][105];
inline int id(int x, int y) { return (x - 1) * m + y; }
int main() {
  std::ios::sync_with_stdio(0), std::cin.tie(0), std::cout.tie(0);
  std::cin >> n >> m, s = n * m + 1, t = s + 1;
  rep(i, 1, n) std::cin >> S[i] + 1;
  rep(i, 1, n) rep(j, 1, m) if (S[i][j] != '#') {
    if (S[i][j] == 'o')
      add(s, id(i, j), 1, 0);
    if (i < n && S[i + 1][j] != '#')
      add(id(i, j), id(i + 1, j), 2e9, 1);
    if (j < m && S[i][j + 1] != '#')
      add(id(i, j), id(i, j + 1), 2e9, 1);
    add(id(i, j), t, 1, 0);
  }
  std::cout << mcmf(s, t).second << '\\n';
  return 0;
}


#include <bits/stdc++.h>
#define LL long long
#define PII pair<int, int>
#define PLL pair<LL, LL>
#define all_of(v) (v).begin(), (v).end()
#define sort_unique(c)                                                         \\
  (sort(c.begin(), c.end()),                                                   \\
   c.resize(distance(c.begin(), unique(c.begin(), c.end()))))
#define fi first
#define se second
// const LL INF = (LL) 1e9 + 8763;
// const LL MOD = (LL) 1e9 + 7;
using namespace std;
mt19937 rng(chrono::steady_clock::now().time_since_epoch().count());
// #define int LL
const int INF = 20000; // LL

struct KM {
  // Maximum Bipartite Weighted Matching (Perfect Match)
  static const int MXN = 2505;
  int n, match[MXN], vx[MXN], vy[MXN];
  int edge[MXN][MXN], lx[MXN], ly[MXN], slack[MXN];
  // ^^^^ LL
  void init(int _n) {
    n = _n;
    for (int i = 0; i < n; i++)
      for (int j = 0; j < n; j++)
        edge[i][j] = 0;
  }
  void addEdge(int x, int y, int w) // LL
  {
    edge[x][y] = w;
  }
  bool DFS(int x) {
    vx[x] = 1;
    for (int y = 0; y < n; y++) {
      if (vy[y])
        continue;
      if (lx[x] + ly[y] > edge[x][y]) {
        slack[y] = min(slack[y], lx[x] + ly[y] - edge[x][y]);
      } else {
        vy[y] = 1;
        if (match[y] == -1 || DFS(match[y])) {
          match[y] = x;
          return true;
        }
      }
    }
    return false;
  }
  int solve() {
    fill(match, match + n, -1);
    fill(lx, lx + n, -INF);
    fill(ly, ly + n, 0);
    for (int i = 0; i < n; i++)
      for (int j = 0; j < n; j++)
        lx[i] = max(lx[i], edge[i][j]);
    for (int i = 0; i < n; i++) {
      fill(slack, slack + n, INF);
      while (true) {
        fill(vx, vx + n, 0);
        fill(vy, vy + n, 0);
        if (DFS(i))
          break;
        int d = INF; // long long
        for (int j = 0; j < n; j++)
          if (!vy[j])
            d = min(d, slack[j]);
        for (int j = 0; j < n; j++) {
          if (vx[j])
            lx[j] -= d;
          if (vy[j])
            ly[j] += d;
          else
            slack[j] -= d;
        }
      }
    }
    int res = 0;
    for (int i = 0; i < n; i++)
      res += edge[match[i]][i];
    return res;
  }
} km;

const int MAXN = 55;
int n, m, vis[MAXN][MAXN];
char mp[MAXN][MAXN];

void dfs(int r, int c, int fr, int fc) {
  vis[r][c] = 1;
  km.addEdge(fr * m + fc, r * m + c, (r - fr) + (c - fc));
  if (r != n - 1 && mp[r + 1][c] != '#') {
    dfs(r + 1, c, fr, fc);
  }
  if (c != m - 1 && mp[r][c + 1] != '#') {
    dfs(r, c + 1, fr, fc);
  }
}

void solve() {
  cin >> n >> m;
  for (int i = 0; i < n; i++) {
    for (int j = 0; j < m; j++) {
      cin >> mp[i][j];
    }
  }

  km.init(n * m);
  for (int i = 0; i < n; i++) {
    for (int j = 0; j < m; j++) {
      if (mp[i][j] == 'o') {
        memset(vis, 0, sizeof(vis));
        dfs(i, j, i, j);
        for (int k = 0; k < n; k++) {
          for (int l = 0; l < m; l++) {
            if (!vis[k][l]) {
              km.addEdge(i * m + j, k * m + l, -INF);
            }
          }
        }
      }
    }
  }

  cout << km.solve() << '\\n';
}

signed main() {
  ios_base::sync_with_stdio(0);
  cin.tie(0);

  int tc = 1;
  //	cin >> tc;
  for (int i = 1; i <= tc; i++) {
    solve();
  }

  return 0;
}

#include <bits/stdc++.h>
#define LL long long
#define PII pair<int, int>
#define PLL pair<LL, LL>
#define all_of(v) (v).begin(), (v).end()
#define sort_unique(c)                                                         \\
  (sort(c.begin(), c.end()),                                                   \\
   c.resize(distance(c.begin(), unique(c.begin(), c.end()))))
#define fi first
#define se second
// const LL INF = (LL) 1e9 + 8763;
// const LL MOD = (LL) 1e9 + 7;
using namespace std;
mt19937 rng(chrono::steady_clock::now().time_since_epoch().count());
// #define int LL
const int MAXV = 2505;
const int INF = 1e8;

struct Min_cost_flow {
// 0-based
#define fi first
#define se second
  struct Edge {
    int to, cap;
    int cost, rev;
  };

  int V, E;
  vector<Edge> G[MAXV];
  PII pre[MAXV];
  int flow[MAXV], dist[MAXV];
  bool inque[MAXV];

  void init(int _V) {
    V = _V;
    for (int i = 0; i <= V; i++)
      G[i].clear();
  }
  PII add_edge(int fr, int to, int cap, int cost) {
    int a = G[fr].size(), b = G[to].size();
    G[fr].push_back({to, cap, cost, b});
    G[to].push_back({fr, 0, -cost, a});
    return {fr, (int)G[fr].size() - 1};
  }
  bool SPFA(int s, int t, int &ans_flow, int &ans_cost) {
    queue<int> que;
    for (int i = 0; i <= V; i++) {
      dist[i] = INF;
      inque[i] = false;
    }
    dist[s] = 0;
    flow[s] = INF;
    inque[s] = true;
    que.push(s);
    while (!que.empty()) {
      int v = que.front();
      que.pop();
      inque[v] = false;
      for (int i = 0; i < G[v].size(); i++) {
        const Edge &e = G[v][i];
        if (e.cap > 0 && dist[v] + e.cost < dist[e.to]) {
          flow[e.to] = min(flow[v], e.cap);
          dist[e.to] = dist[v] + e.cost;
          pre[e.to] = {v, i};
          if (!inque[e.to])
            que.push(e.to), inque[e.to] = true;
        }
      }
    }
    if (dist[t] == INF)
      return false;
    // if (dist[t]>=0) return false;
    //  Add above line -> min cost first, then max flow (priority)
    //  Without        -> max flow first, then min cost

    int v = t, f = flow[t];
    ans_flow += flow[t];
    ans_cost += (dist[t] * flow[t]);
    while (v != s) {
      Edge &e = G[pre[v].fi][pre[v].se];
      e.cap -= f;
      G[v][e.rev].cap += f;
      v = pre[v].fi;
    }
    return true;
  }
  pair<int, int> mcmf(int s, int t) {
    int ans_flow = 0, ans_cost = 0;
    while (SPFA(s, t, ans_flow, ans_cost))
      ;
    return make_pair(ans_flow, ans_cost);
  }
} algo;

const int MAXN = 55;
int n, m, vis[MAXN][MAXN];
char mp[MAXN][MAXN];

void solve() {
  cin >> n >> m;
  for (int i = 0; i < n; i++) {
    for (int j = 0; j < m; j++) {
      cin >> mp[i][j];
    }
  }

  int src = n * m, tgt = src + 1;
  algo.init(tgt + 1);
  for (int i = 0; i < n; i++) {
    for (int j = 0; j < m; j++) {
      if (mp[i][j] == 'o') {
        algo.add_edge(src, i * m + j, 1, 0);
      }
      if (mp[i][j] != '#') {
        if (i != n - 1 && mp[i + 1][j] != '#') {
          algo.add_edge(i * m + j, (i + 1) * m + j, INF, -1);
        }
        if (j != m - 1 && mp[i][j + 1] != '#') {
          algo.add_edge(i * m + j, i * m + (j + 1), INF, -1);
        }
        algo.add_edge(i * m + j, tgt, 1, 0);
      }
    }
  }

  auto res = algo.mcmf(src, tgt);
  //	cout << "Flow " << res.fi << '\\n';
  cout << -res.se << '\\n';
}

signed main() {
  ios_base::sync_with_stdio(0);
  cin.tie(0);

  int tc = 1;
  //	cin >> tc;
  for (int i = 1; i <= tc; i++) {
    solve();
  }

  return 0;
}


#include <cassert>
#include <cstdio>
#include <limits>
#include <queue>
#include <tuple>
#include <utility>
#include <vector>
using namespace std;

struct MinCostFlowGraph {
private:
  using ll = long long;
  struct edge {
    int to;
    ll cap, cost;
    int r_idx;
    edge(int t, ll cap, ll cost, int r)
        : to(t), cap(cap), cost(cost), r_idx(r) {}
  };
  vector<vector<edge>> G;
  int sz;
  vector<ll> calc_potential(int from) {
    queue<int> Q;
    Q.emplace(from);
    vector<ll> ret(sz, numeric_limits<int>::max() / 2);
    ret[from] = 0;
    vector<int> d_in(sz, 0);
    for (int i = 0; i < sz; ++i) {
      for (auto e : G[i]) {
        if (e.cap <= 0)
          continue;
        ++d_in[e.to];
      }
    }
    while (Q.size()) {
      auto v = Q.front();
      Q.pop();
      for (auto e : G[v]) {
        if (e.cap <= 0)
          continue;
        int v_ = e.to;
        ret[v_] = min(ret[v_], ret[v] + e.cost);
        --d_in[v_];
        if (!d_in[v_])
          Q.emplace(v_);
      }
    }
    return ret;
  }

public:
  MinCostFlowGraph(int n) : G(n), sz(n) {}

  void add_edge(int from, int to, ll cap, ll cost) {
    int i = G[to].size(), i_ = G[from].size();
    G[from].emplace_back(to, cap, cost, i);
    G[to].emplace_back(from, 0, -cost, i_);
  }

  ll min_cost_flow(int from, int to, ll f) {
    ll ans = 0;
    const ll INF = numeric_limits<int>::max() / 2;
    vector<ll> potential = calc_potential(from);
    while (f > 0) {
      vector<ll> dist(sz, INF);
      dist[from] = 0;
      vector<int> prev_v(sz, -1);
      vector<int> prev_e(sz, -1);
      priority_queue<pair<ll, int>, vector<pair<ll, int>>, greater<>> pq;
      pq.emplace(0, from);
      while (pq.size()) {
        auto [d, v] = pq.top();
        // d *= -1;
        pq.pop();
        if (dist[v] < d)
          continue;
        for (size_t i = 0; i < G[v].size(); ++i) {
          const auto &e = G[v][i];
          if (e.cap == 0)
            continue;
          int v_ = e.to;
          ll d_ = d + e.cost + potential[v] - potential[v_];
          if (dist[v_] <= d_)
            continue;
          dist[v_] = d_;
          prev_v[v_] = v;
          prev_e[v_] = i;
          // pq.emplace(-d_,e.to);
          pq.emplace(d_, e.to);
        }
      }
      if (dist[to] >= INF)
        return -1;
      for (int i = 0; i < sz; ++i)
        potential[i] += dist[i];
      int v = to;
      ll flow = f;
      while (v != from) {
        int v_ = prev_v[v];
        flow = min(flow, G[v_][prev_e[v]].cap);
        v = v_;
      }
      v = to;
      while (v != from) {
        int v_ = prev_v[v];
        auto &e = G[v_][prev_e[v]];
        e.cap -= flow;
        ans += flow * e.cost;
        G[v][e.r_idx].cap += flow;
        v = v_;
      }
      f -= flow;
    }
    return ans;
  }
};

#include <iostream>
#include <vector>
using namespace std;

int main() {
  int N, M;
  cin >> N >> M;
  vector<string> S(N);
  for (int i = 0; i < N; ++i) {
    cin >> S[i];
  }
  MinCostFlowGraph G(N * M + 2);
  int source = N * M, sink = source + 1;
  int c = 0, INF = 1e9;
  for (int i = 0; i < N; ++i) {
    for (int j = 0; j < N; ++j) {
      if (S[i][j] == '#')
        continue;
      int v = i * M + j;
      if (S[i][j] == 'o') {
        ++c;
        G.add_edge(source, v, 1, 0);
      }
      if (i + 1 < N)
        G.add_edge(v, v + M, INF, -1);
      if (j + 1 < M)
        G.add_edge(v, v + 1, INF, -1);
      G.add_edge(v, sink, 1, 0);
    }
  }
  cout << -G.min_cost_flow(source, sink, c) << '\\n';
}

#include <cassert>
#include <cstdio>
#include <limits>
#include <queue>
#include <tuple>
#include <utility>
#include <vector>
using namespace std;

struct MinCostFlowGraph {
private:
  using ll = long long;
  struct edge {
    int to;
    ll cap, cost;
    int r_idx;
    edge(int t, ll cap, ll cost, int r)
        : to(t), cap(cap), cost(cost), r_idx(r) {}
  };
  vector<vector<edge>> G;
  int sz;
  vector<ll> calc_potential(int from) {
    queue<int> Q;
    Q.emplace(from);
    vector<ll> ret(sz, numeric_limits<int>::max() / 2);
    ret[from] = 0;
    vector<int> d_in(sz, 0);
    for (int i = 0; i < sz; ++i) {
      for (auto e : G[i]) {
        if (e.cap <= 0)
          continue;
        ++d_in[e.to];
      }
    }
    while (Q.size()) {
      auto v = Q.front();
      Q.pop();
      for (auto e : G[v]) {
        if (e.cap <= 0)
          continue;
        int v_ = e.to;
        ret[v_] = min(ret[v_], ret[v] + e.cost);
        --d_in[v_];
        if (!d_in[v_])
          Q.emplace(v_);
      }
    }
    return ret;
  }

public:
  MinCostFlowGraph(int n) : G(n), sz(n) {}

  void add_edge(int from, int to, ll cap, ll cost) {
    int i = G[to].size(), i_ = G[from].size();
    G[from].emplace_back(to, cap, cost, i);
    G[to].emplace_back(from, 0, -cost, i_);
  }

  ll min_cost_flow(int from, int to, ll f) {
    ll ans = 0;
    const ll INF = numeric_limits<int>::max() / 2;
    vector<ll> potential = calc_potential(from);
    while (f > 0) {
      vector<ll> dist(sz, INF);
      dist[from] = 0;
      vector<int> prev_v(sz, -1);
      vector<int> prev_e(sz, -1);
      priority_queue<pair<ll, int>, vector<pair<ll, int>>, greater<>> pq;
      pq.emplace(0, from);
      while (pq.size()) {
        auto [d, v] = pq.top();
        // d *= -1;
        pq.pop();
        if (dist[v] < d)
          continue;
        for (size_t i = 0; i < G[v].size(); ++i) {
          const auto &e = G[v][i];
          if (e.cap == 0)
            continue;
          int v_ = e.to;
          ll d_ = d + e.cost + potential[v] - potential[v_];
          if (dist[v_] <= d_)
            continue;
          dist[v_] = d_;
          prev_v[v_] = v;
          prev_e[v_] = i;
          // pq.emplace(-d_,e.to);
          pq.emplace(d_, e.to);
        }
      }
      // if(dist[to] >= INF) return -1;
      for (int i = 0; i < sz; ++i)
        potential[i] += dist[i];
      int v = to;
      ll flow = f;
      while (v != from) {
        int v_ = prev_v[v];
        flow = min(flow, G[v_][prev_e[v]].cap);
        v = v_;
      }
      v = to;
      while (v != from) {
        int v_ = prev_v[v];
        auto &e = G[v_][prev_e[v]];
        e.cap -= flow;
        ans += flow * e.cost;
        G[v][e.r_idx].cap += flow;
        v = v_;
      }
      f -= flow;
    }
    return ans;
  }
};

#include <iostream>
#include <vector>
using namespace std;

int main() {
  int N, M;
  cin >> N >> M;
  vector<string> S(N);
  for (int i = 0; i < N; ++i) {
    cin >> S[i];
  }
  MinCostFlowGraph G(N * M + 2);
  int source = N * M, sink = source + 1;
  int c = 0, INF = 1e9;
  for (int i = 0; i < N; ++i) {
    for (int j = 0; j < M; ++j) {
      if (S[i][j] == '#')
        continue;
      int v = i * M + j;
      if (S[i][j] == 'o') {
        ++c;
        G.add_edge(source, v, 1, 0);
      }
      if (i + 1 < N)
        G.add_edge(v, v + M, INF, -1);
      if (j + 1 < M)
        G.add_edge(v, v + 1, INF, -1);
      G.add_edge(v, sink, 1, 0);
    }
  }
  cout << -G.min_cost_flow(source, sink, c) << '\\n';
}


#include <bits/stdc++.h>
#pragma GCC optimization("Ofast")
#pragma GCC optimization("unroll-loops")
using namespace std;
#define int long long
#define rep(i, n) for (int i = 0; i < n; i++)
#define REP(i, n) for (int i = 1; i < n; i++)
#define rev(i, n) for (int i = n - 1; i >= 0; i--)
#define all(v) v.begin(), v.end()
#define P pair<int, int>
#define len(s) (int)s.size()

template <class T> inline bool chmin(T &a, T b) {
  if (a > b) {
    a = b;
    return true;
  }
  return false;
}
template <class T> inline bool chmax(T &a, T b) {
  if (a < b) {
    a = b;
    return true;
  }
  return false;
}
constexpr int mod = 1e9 + 7;
constexpr long long inf = 3e18;
struct PrimalDual {
  struct edge {
    int to, cap, cost, rev;
  };
  vector<vector<edge>> graph;
  void add_edge(int from, int to, int cap, int cost) {
    graph[from].push_back({to, cap, cost, len(graph[to])});
    graph[to].push_back({from, 0ll, -cost, len(graph[from]) - 1});
  }
  int minCostFlow(int s, int t, int f) {
    int V = len(graph);
    vector<int> potential(V), minCost, prevv(V, -1), preve(V, -1);
    vector<bool> used(V);
    int res = 0;
    while (f > 0) {
      minCost.assign(V, inf);
      used.assign(V, 0);
      minCost[s] = 0;
      rep(_, V - 1) {
        int mn = inf, idx;
        rep(i, V) if (!used[i] && chmin(mn, minCost[i])) idx = i;
        used[idx] = true;
        rep(i, len(graph[idx])) {
          edge &e = graph[idx][i];
          int nextcost = mn + e.cost + potential[idx] - potential[e.to];
          if (e.cap > 0 && minCost[e.to] > nextcost) {
            minCost[e.to] = nextcost;
            prevv[e.to] = idx;
            preve[e.to] = i;
          }
        }
      }
      if (minCost[t] == inf)
        return -1;
      rep(i, V) potential[i] += minCost[i];
      int addflow = f;
      for (int i = t; i != s; i = prevv[i])
        chmin(addflow, graph[prevv[i]][preve[i]].cap);
      f -= addflow;
      res += addflow * potential[t];
      for (int i = t; i != s; i = prevv[i]) {
        edge &e = graph[prevv[i]][preve[i]];
        e.cap -= addflow;
        graph[i][e.rev].cap += addflow;
      }
    }
    return res;
  }
  PrimalDual(int V) : graph(V){};
};

int N, M;
char c[55][55];
bool used[55][55];
signed main() {
  cin.tie(0);
  ios::sync_with_stdio(false);
  cin >> N >> M;
  rep(i, N) rep(j, M) cin >> c[i][j];
  PrimalDual F(2 * N * M + 2);
  int cnt = 0;
  rep(i, N) rep(j, M) {
    if (c[i][j] == 'o') {
      cnt++;
      memset(used, 0, sizeof(used));
      F.add_edge(2 * N * M, i * M + j, 1, 0);
      used[i][j] = true;
      rep(k, N) rep(l, M) {
        if (used[k][l]) {
          F.add_edge(i * M + j, N * M + k * M + l, 1, mod - (k - i + l - j));
        }
        if (c[k + 1][l] != '#')
          used[k + 1][l] |= used[k][l];
        if (c[k][l + 1] != '#')
          used[k][l + 1] |= used[k][l];
      }
    }
    F.add_edge(N * M + i * M + j, 2 * N * M + 1, 1, 0);
  }
  cout << cnt * mod - F.minCostFlow(2 * N * M, 2 * N * M + 1, cnt) << "\\n";
}

#include <bits/stdc++.h>
#pragma GCC optimization("Ofast")
#pragma GCC optimization("unroll-loops")
using namespace std;
#define int long long
#define rep(i, n) for (int i = 0; i < n; i++)
#define REP(i, n) for (int i = 1; i < n; i++)
#define rev(i, n) for (int i = n - 1; i >= 0; i--)
#define all(v) v.begin(), v.end()
#define P pair<int, int>
#define len(s) (int)s.size()

template <class T> inline bool chmin(T &a, T b) {
  if (a > b) {
    a = b;
    return true;
  }
  return false;
}
template <class T> inline bool chmax(T &a, T b) {
  if (a < b) {
    a = b;
    return true;
  }
  return false;
}
constexpr int mod = 1e9 + 7;
constexpr long long inf = 3e18;
struct PrimalDual {
  struct edge {
    int to, cap, cost, rev;
  };
  vector<vector<edge>> graph;
  void add_edge(int from, int to, int cap, int cost) {
    graph[from].push_back({to, cap, cost, len(graph[to])});
    graph[to].push_back({from, 0ll, -cost, len(graph[from]) - 1});
  }
  int minCostFlow(int s, int t, int f) {
    int V = len(graph);
    vector<int> potential(V), minCost, prevv(V, -1), preve(V, -1);
    vector<bool> used(V);
    int res = 0;
    while (f > 0) {
      minCost.assign(V, inf);
      used.assign(V, 0);
      minCost[s] = 0;
      rep(_, V - 1) {
        int mn = inf, idx;
        rep(i, V) if (!used[i] && chmin(mn, minCost[i])) idx = i;
        used[idx] = true;
        rep(i, len(graph[idx])) {
          edge &e = graph[idx][i];
          int nextcost = mn + e.cost + potential[idx] - potential[e.to];
          if (e.cap > 0 && minCost[e.to] > nextcost) {
            minCost[e.to] = nextcost;
            prevv[e.to] = idx;
            preve[e.to] = i;
          }
        }
      }
      if (minCost[t] == inf)
        return -1;
      rep(i, V) potential[i] += minCost[i];
      int addflow = f;
      for (int i = t; i != s; i = prevv[i])
        chmin(addflow, graph[prevv[i]][preve[i]].cap);
      f -= addflow;
      res += addflow * potential[t];
      for (int i = t; i != s; i = prevv[i]) {
        edge &e = graph[prevv[i]][preve[i]];
        e.cap -= addflow;
        graph[i][e.rev].cap += addflow;
      }
    }
    return res;
  }
  PrimalDual(int V) : graph(V){};
};

int N, M;
char c[55][55];
bool used[55][55];
signed main() {
  cin.tie(0);
  ios::sync_with_stdio(false);
  cin >> N >> M;
  rep(i, N) rep(j, M) cin >> c[i][j];
  PrimalDual F(N * M + 2);
  int cnt = 0;
  rep(i, N) rep(j, M) {
    if (c[i][j] == 'o') {
      cnt++;
      memset(used, 0, sizeof(used));
      F.add_edge(N * M, i * M + j, 1, 0);
      F.add_edge(i * M + j, N * M + 1, 1, mod);
      used[i][j] = true;
      rep(k, N) rep(l, M) {
        if ((k != i || l != j) && used[k][l]) {
          F.add_edge(i * M + j, k * M + l, 1, mod - (k - i + l - j));
        }
        if (c[k + 1][l] != '#')
          used[k + 1][l] |= used[k][l];
        if (c[k][l + 1] != '#')
          used[k][l + 1] |= used[k][l];
      }
    } else
      F.add_edge(i * M + j, N * M + 1, 1, 0);
  }
  cout << cnt * mod - F.minCostFlow(N * M, N * M + 1, cnt) << "\\n";
}


// Original Code:
// #include <self/utility>
// #include <self/debug>
// #include <self/mcmf>
// using namespace std;
// int n,m;
// char c[55][55];
// const int dx[]={0,1};
// const int dy[]={1,0};
// int dist[55][55];
// int id[55][55];
// int rhsNum;
// vector <pii> vec[105];
//
// inline bool out(int x,int y)
//{
//	return (x>=n || y>=m);
// }
//
// inline int getID(int x,int y)
//{
//	return (id[x][y]==-1?id[x][y]=rhsNum++:id[x][y]);
// }
//
// inline void bfs(int sx,int sy,int id)
//{
//	queue <tuple<int,int> > que;
//	que.push(make_tuple(sx,sy));
//	for(int i=0;i<n;i++)
//	{
//		for(int j=0;j<m;j++)
//		{
//			dist[i][j]=-inf;
//		}
//	}
////	memset(dist,-1,sizeof(dist));
//	dist[sx][sy]=0;
//	while(que.size())
//	{
//		int x,y;
//		tie(x,y)=que.front();
//		que.pop();
//		for(int i=0;i<2;i++)
//		{
//			int nx=x+dx[i];
//			int ny=y+dy[i];
//			if(out(nx,ny) || dist[nx][ny]!=-inf || c[nx][ny]=='#')
//continue; 			dist[nx][ny]=dist[x][y]+1; 			que.push(make_tuple(nx,ny));
//		}
//	}
//	vector <tuple<int,int,int> > vSort;
//	for(int i=0;i<n;i++)
//	{
//		for(int j=0;j<n;j++)
//		{
//			vSort.push_back(make_tuple(dist[i][j],i,j));
//		}
//	}
//	sort(all(vSort));
//	reverse(all(vSort));
//	for(int i=0;i<min(100,(int)vSort.size());i++)
//	{
//		vec[id].push_back(mp(getID(get<1>(vSort[i]),get<2>(vSort[i])),get<0>(vSort[i])));
//	}
//}
//
// int main()
//{
////	freopen("input.txt","r",stdin);
//	memset(id,-1,sizeof(id));
//	cin>>n>>m;
//	for(int i=0;i<n;i++)
//	{
//		scanf("%s",c[i]);
//	}
//	NetworkWithCost g;
//	g.init(n*m+2);
//	int src=n*m,dst=src+1;
//	g.feedsd(src,dst);
//	for(int i=0;i<n;i++)
//	{
//		for(int j=0;j<m;j++)
//		{
//			if(c[i][j]=='#') continue;
//			if(!out(i+1,j) && c[i+1][j]!='#')
//			{
//				g.addEdge(i*m+j,(i+1)*m+j,inf,-1);
//			}
//			if(!out(i,j+1) && c[i][j+1]!='#')
//			{
//				g.addEdge(i*m+j,(i)*m+(j+1),inf,-1);
//			}
//			if(c[i][j]=='o') g.addEdge(src,i*m+j,1,0);
//			g.addEdge(i*m+j,dst,1,0);
//		}
//	}
////	int ids=0;
////	for(int i=0;i<n;i++)
////	{
////		for(int j=0;j<m;j++)
////		{
////			if(c[i][j]=='o')
////			{
////				bfs(i,j,ids);
////				ids++;
//////				cout<<mp(i,j)<<" is "<<ids<<endl;
//////				for(int kx=0;kx<n;kx++)
//////				{
//////					for(int ky=0;ky<m;ky++)
//////					{
//////						cout<<dist[kx][ky]<<' ';
//////					}
//////					cout<<endl;
//////				}
//////				cout<<endl;
////			}
////		}
////	}
////	int nodes=ids+rhsNum+2;
////	int src=nodes-2,dst=nodes-1;
////	NetworkWithCost g;
////	g.init(nodes);
////	g.feedsd(nodes-2,nodes-1);
////	for(int i=0;i<ids;i++)
////	{
////		for(auto [x,y]:vec[i])
////		{
////			g.addEdge(i,x+ids,1,-y);
//////			cout<<i<<"->"<<x<<":cost="<<y<<endl;
////		}
////	}
////	for(int i=0;i<ids;i++)
////	{
////		g.addEdge(src,i,1,0);
////	}
////	for(int i=0;i<rhsNum;i++)
////	{
////		g.addEdge(ids+i,dst,1,0);
////	}
//	MCMF d;
//	d.init(g);
//	cout<<-d.run().second<<endl;
//	return 0;
//}

// substituted with C++ Inliner
#ifndef _SELF_UTILITY
#define _SELF_UTILITY 1
#include <algorithm>
#include <assert.h>
#include <bitset>
#include <cmath>
#include <iostream>
#include <map>
#include <numeric>
#include <queue>
#include <set>
#include <stack>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <string>
#include <time.h>
#include <vector>
#define Endl endl
#define mp make_pair
#define ll long long
#define ull unsigned long long
#define pii pair<int, int>
#define over(A)                                                                \\
  {                                                                            \\
    cout << A << endl;                                                         \\
    exit(0);                                                                   \\
  }
#define all(A) A.begin(), A.end()
#define quickcin ios_base::sync_with_stdio(false);
const int mod = 998244353;
const int gmod = 2;
const int inf = 1039074182;
const ll llinf = 1LL * inf * inf;
template <typename T1, typename T2> inline void chmin(T1 &x, T2 b) {
  if (b < x)
    x = b;
}
template <typename T1, typename T2> inline void chmax(T1 &x, T2 b) {
  if (b > x)
    x = b;
}
template <typename T1, typename T2> inline void chadd(T1 &x, T2 b) {
  x += b;
  if (x >= mod)
    x -= mod;
}
template <typename T1, typename T2> inline void chmul(T1 &x, T2 b) {
  x = 1LL * x * b % mod;
}
template <typename T1, typename T2> inline void chmod(T1 &x, T2 b) {
  x %= b, x += b;
  if (x >= b)
    x -= b;
}
#endif

#ifndef _SELF_DEBUG
#define _SELF_DEBUG 1
#ifndef _SELF_OPERATOR
#define _SELF_OPERATOR 1
using namespace std;
template <typename T> ostream &operator<<(ostream &cout, vector<T> vec) {
  cout << "{";
  for (int i = 0; i < (int)vec.size(); i++) {
    cout << vec[i];
    if (i != (int)vec.size() - 1)
      cout << ',';
  }
  cout << "}";
  return cout;
}

template <typename T1, typename T2>
ostream &operator<<(ostream &cout, pair<T1, T2> p) {
  cout << "(" << p.first << ',' << p.second << ")";
  return cout;
}

template <typename T, typename T2>
ostream &operator<<(ostream &cout, set<T, T2> s) {
  vector<T> t;
  for (auto x : s)
    t.push_back(x);
  cout << t;
  return cout;
}

template <typename T> ostream &operator<<(ostream &cout, multiset<T> s) {
  vector<T> t;
  for (auto x : s)
    t.push_back(x);
  cout << t;
  return cout;
}

template <typename T> ostream &operator<<(ostream &cout, queue<T> q) {
  vector<T> t;
  while (q.size()) {
    t.push_back(q.front());
    q.pop();
  }
  cout << t;
  return cout;
}

template <typename T1, typename T2>
ostream &operator<<(ostream &cout, map<T1, T2> m) {
  for (auto &x : m) {
    cout << "Key: " << x.first << ' ' << "Value: " << x.second << endl;
  }
  return cout;
}

template <typename T> T operator*(vector<T> v1, vector<T> v2) {
  assert(v1.size() == v2.size());
  int n = v1.size();
  T res = 0;
  for (int i = 0; i < n; i++) {
    res += v1[i] * v2[i];
  }
  return res;
}

template <typename T1, typename T2>
pair<T1, T2> operator+(pair<T1, T2> x, pair<T1, T2> y) {
  return make_pair(x.first + y.first, x.second + y.second);
}

template <typename T1, typename T2>
void operator+=(pair<T1, T2> &x, pair<T1, T2> y) {
  x.first += y.first;
  x.second += y.second;
}

template <typename T1, typename T2> pair<T1, T2> operator-(pair<T1, T2> x) {
  return make_pair(-x.first, -x.second);
}

template <typename T> vector<vector<T>> operator~(vector<vector<T>> vec) {
  vector<vector<T>> v;
  int n = vec.size(), m = vec[0].size();
  v.resize(m);
  for (int i = 0; i < m; i++) {
    v[i].resize(n);
  }
  for (int i = 0; i < m; i++) {
    for (int j = 0; j < n; j++) {
      v[i][j] = vec[j][i];
    }
  }
  return v;
}
#endif

void print0x(int x) {
  std::vector<int> vec;
  while (x) {
    vec.push_back(x & 1);
    x >>= 1;
  }
  std::reverse(vec.begin(), vec.end());
  for (int i = 0; i < (int)vec.size(); i++) {
    std::cout << vec[i];
  }
  std::cout << ' ';
}

template <typename T> void print0x(T x, int len) {
  std::vector<int> vec;
  while (x) {
    vec.push_back(x & 1);
    x >>= 1;
  }
  reverse(vec.begin(), vec.end());
  for (int i = vec.size(); i < len; i++) {
    putchar('0');
  }
  for (int i = 0; i < vec.size(); i++) {
    std::cout << vec[i];
  }
  std::cout << ' ';
}
#endif

struct NetworkWithCost {
  struct Edge {
    int vertex;
    int flow;
    int cost;
    int inv;
  };
  vector<Edge> *edges;
  inline void addEdge(int x, int y, int limit, int cost) {
    Edge edge;
    edge.cost = cost;
    edge.flow = limit;
    edge.vertex = y;
    edge.inv = (int)edges[y].size();
    edges[x].push_back(edge);
    edge.vertex = x;
    edge.flow = 0;
    edge.cost = -cost;
    edge.inv = (int)edges[x].size() - 1;
    edges[y].push_back(edge);
  }
  int src, dst;
  int n;
  void init(int _n) {
    n = _n;
    edges = new vector<Edge>[n];
    src = dst = -1;
  }
  void feedsd(int _src, int _dst) {
    src = _src;
    dst = _dst;
  }
  void clear() {
    for (int i = 0; i < n; i++) {
      edges[i].clear();
    }
    src = dst = -1;
  }
};

namespace MCMFSpace {
void operator+=(pii &a, const pii &b) {
  a.first += b.first;
  a.second += b.second;
}
} // namespace MCMFSpace

struct MCMF {
  const int DistInf = 1039074182;
  NetworkWithCost g;
  int *dist;
  bool *visit;
  int *cur;
  queue<int> que;
  inline void init(NetworkWithCost &_g) {
    g = _g;
    dist = new int[g.n + 5];
    visit = new bool[g.n + 5];
    cur = new int[g.n + 5];
  }

  bool bellmanford() {
    //	cout<<"Bf started";
    for (int i = 0; i < g.n; i++) {
      dist[i] = inf;
    }
    dist[g.src] = 0;
    for (int T = 0; T < g.n; T++) {
      for (int i = 0; i < g.n; i++) {
        if (dist[i] == inf)
          continue;
        for (auto &e : g.edges[i]) {
          if (e.flow == 0)
            continue;
          if (dist[e.vertex] > dist[i] + e.cost) {
            dist[e.vertex] = dist[i] + e.cost;
          }
        }
      }
    }
    //	system("pause");
    return (dist[g.dst] < inf);
  }

  bool dijkstra() {
    for (int i = 0; i < g.n; i++) {
      dist[i] = -1;
    }
    dist[g.src] = 0;
    priority_queue<pii, vector<pii>, greater<pii>> pq;
    pq.push(mp(0, 0));
    while (pq.size()) {
      int x = pq.top().second;
      int cost = pq.top().first;
      pq.pop();
      if (dist[x] != cost)
        continue;
      for (auto &e : g.edges[x]) {
        if (e.flow == 0)
          continue;
        if (dist[e.vertex] > cost + e.cost || dist[e.vertex] == -1) {
          dist[e.vertex] = cost + e.cost;
          pq.push(mp(dist[e.vertex], e.vertex));
        }
      }
    }
    return (dist[g.dst] != -1);
  }

  pair<int, int> dfs(int x, int flow) {
    if (x == g.dst)
      return mp(flow, 0);
    visit[x] = 1;
    pii res = {0, 0};
    for (int &i = cur[x]; i < (int)g.edges[x].size(); i++) {
      int u = g.edges[x][i].vertex;
      int c = g.edges[x][i].cost;
      if (visit[u])
        continue;
      if (dist[u] != dist[x] + c)
        continue;
      if (g.edges[x][i].flow == 0)
        continue;
      pii f = dfs(u, min(flow, g.edges[x][i].flow));
      flow -= f.first;
      res += f;
      res.second += g.edges[x][i].cost * f.first;
      g.edges[x][i].flow -= f.first;
      g.edges[u][g.edges[x][i].inv].flow += f.first;
      if (flow == 0)
        break;
    }
    visit[x] = 0;
    return res;
  }

  pii run() {
    pair<int, int> x = mp(0, 0);
    for (int i = 0; i < g.n; i++) {
      visit[i] = 0;
    }
    while (bellmanford()) {
      //			cout<<g.n<<endl;
      //			for(int i=0;i<g.n;i++)
      //			{
      //				cout<<dist[i]<<' ';
      //			}
      //			cout<<endl;
      //			Sleep(1000);
      for (int i = 0; i < g.n; i++) {
        assert(visit[i] == 0);
      }
      for (int i = 0; i < g.n; i++) {
        cur[i] = 0;
      }
      pair<int, int> f = dfs(g.src, inf);
      //			cout<<"flow="<<f<<endl;
      x += f;
    }
    return x;
  }
};
using namespace std;
int n, m;
char c[55][55];
const int dx[] = {0, 1};
const int dy[] = {1, 0};
int dist[55][55];
int id[55][55];
int rhsNum;
vector<pii> vec[105];

inline bool out(int x, int y) { return (x >= n || y >= m); }

inline int getID(int x, int y) {
  return (id[x][y] == -1 ? id[x][y] = rhsNum++ : id[x][y]);
}

inline void bfs(int sx, int sy, int id) {
  queue<tuple<int, int>> que;
  que.push(make_tuple(sx, sy));
  for (int i = 0; i < n; i++) {
    for (int j = 0; j < m; j++) {
      dist[i][j] = -inf;
    }
  }
  //	memset(dist,-1,sizeof(dist));
  dist[sx][sy] = 0;
  while (que.size()) {
    int x, y;
    tie(x, y) = que.front();
    que.pop();
    for (int i = 0; i < 2; i++) {
      int nx = x + dx[i];
      int ny = y + dy[i];
      if (out(nx, ny) || dist[nx][ny] != -inf || c[nx][ny] == '#')
        continue;
      dist[nx][ny] = dist[x][y] + 1;
      que.push(make_tuple(nx, ny));
    }
  }
  vector<tuple<int, int, int>> vSort;
  for (int i = 0; i < n; i++) {
    for (int j = 0; j < n; j++) {
      vSort.push_back(make_tuple(dist[i][j], i, j));
    }
  }
  sort(all(vSort));
  reverse(all(vSort));
  for (int i = 0; i < min(100, (int)vSort.size()); i++) {
    vec[id].push_back(
        mp(getID(get<1>(vSort[i]), get<2>(vSort[i])), get<0>(vSort[i])));
  }
}

int main() {
  //	freopen("input.txt","r",stdin);
  memset(id, -1, sizeof(id));
  cin >> n >> m;
  for (int i = 0; i < n; i++) {
    scanf("%s", c[i]);
  }
  NetworkWithCost g;
  g.init(n * m + 2);
  int src = n * m, dst = src + 1;
  g.feedsd(src, dst);
  for (int i = 0; i < n; i++) {
    for (int j = 0; j < m; j++) {
      if (c[i][j] == '#')
        continue;
      if (!out(i + 1, j) && c[i + 1][j] != '#') {
        g.addEdge(i * m + j, (i + 1) * m + j, inf, -1);
      }
      if (!out(i, j + 1) && c[i][j + 1] != '#') {
        g.addEdge(i * m + j, (i)*m + (j + 1), inf, -1);
      }
      if (c[i][j] == 'o')
        g.addEdge(src, i * m + j, 1, 0);
      g.addEdge(i * m + j, dst, 1, 0);
    }
  }
  //	int ids=0;
  //	for(int i=0;i<n;i++)
  //	{
  //		for(int j=0;j<m;j++)
  //		{
  //			if(c[i][j]=='o')
  //			{
  //				bfs(i,j,ids);
  //				ids++;
  ////				cout<<mp(i,j)<<" is "<<ids<<endl;
  ////				for(int kx=0;kx<n;kx++)
  ////				{
  ////					for(int ky=0;ky<m;ky++)
  ////					{
  ////						cout<<dist[kx][ky]<<' ';
  ////					}
  ////					cout<<endl;
  ////				}
  ////				cout<<endl;
  //			}
  //		}
  //	}
  //	int nodes=ids+rhsNum+2;
  //	int src=nodes-2,dst=nodes-1;
  //	NetworkWithCost g;
  //	g.init(nodes);
  //	g.feedsd(nodes-2,nodes-1);
  //	for(int i=0;i<ids;i++)
  //	{
  //		for(auto [x,y]:vec[i])
  //		{
  //			g.addEdge(i,x+ids,1,-y);
  ////			cout<<i<<"->"<<x<<":cost="<<y<<endl;
  //		}
  //	}
  //	for(int i=0;i<ids;i++)
  //	{
  //		g.addEdge(src,i,1,0);
  //	}
  //	for(int i=0;i<rhsNum;i++)
  //	{
  //		g.addEdge(ids+i,dst,1,0);
  //	}
  MCMF d;
  d.init(g);
  cout << -d.run().second << endl;
  return 0;
}

// Original Code:
// #include <self/utility>
// #include <self/debug>
// #include <self/mcmf>
// using namespace std;
// int n,m;
// char c[55][55];
// const int dx[]={0,1};
// const int dy[]={1,0};
// int dist[55][55];
// int id[55][55];
// int rhsNum;
// vector <pii> vec[105];
//
// inline bool out(int x,int y)
//{
//	return (x>=n || y>=m);
// }
//
// inline int getID(int x,int y)
//{
//	return (id[x][y]==-1?id[x][y]=rhsNum++:id[x][y]);
// }
//
// inline void bfs(int sx,int sy,int id)
//{
//	queue <tuple<int,int> > que;
//	que.push(make_tuple(sx,sy));
//	for(int i=0;i<n;i++)
//	{
//		for(int j=0;j<m;j++)
//		{
//			dist[i][j]=-inf;
//		}
//	}
////	memset(dist,-1,sizeof(dist));
//	dist[sx][sy]=0;
//	while(que.size())
//	{
//		int x,y;
//		tie(x,y)=que.front();
//		que.pop();
//		for(int i=0;i<2;i++)
//		{
//			int nx=x+dx[i];
//			int ny=y+dy[i];
//			if(out(nx,ny) || dist[nx][ny]!=-inf || c[nx][ny]=='#')
//continue; 			dist[nx][ny]=dist[x][y]+1; 			que.push(make_tuple(nx,ny));
//		}
//	}
//	vector <tuple<int,int,int> > vSort;
//	for(int i=0;i<n;i++)
//	{
//		for(int j=0;j<n;j++)
//		{
//			vSort.push_back(make_tuple(dist[i][j],i,j));
//		}
//	}
//	sort(all(vSort));
//	reverse(all(vSort));
//	for(int i=0;i<min(100,(int)vSort.size());i++)
//	{
//		vec[id].push_back(mp(getID(get<1>(vSort[i]),get<2>(vSort[i])),get<0>(vSort[i])));
//	}
//}
//
// int main()
//{
////	freopen("input.txt","r",stdin);
//	memset(id,-1,sizeof(id));
//	cin>>n>>m;
//	for(int i=0;i<n;i++)
//	{
//		scanf("%s",c[i]);
//	}
//	NetworkWithCost g;
//	g.init(n*m+2);
//	int src=n*m,dst=src+1;
//	g.feedsd(src,dst);
//	for(int i=0;i<n;i++)
//	{
//		for(int j=0;j<m;j++)
//		{
//			if(c[i][j]=='#') continue;
//			if(!out(i+1,j) && c[i+1][j]!='#')
//			{
//				g.addEdge(i*m+j,(i+1)*m+j,inf,0);
//			}
//			if(!out(i,j+1) && c[i][j+1]!='#')
//			{
//				g.addEdge(i*m+j,(i)*m+(j+1),inf,0);
//			}
//			if(c[i][j]=='o') g.addEdge(src,i*m+j,1,i+j);
//			g.addEdge(i*m+j,dst,1,-i-j);
//		}
//	}
//	MCMF d;
//	d.init(g);
//	cout<<-d.run().second<<endl;
//	return 0;
//}

// substituted with C++ Inliner
#ifndef _SELF_UTILITY
#define _SELF_UTILITY 1
#include <algorithm>
#include <assert.h>
#include <bitset>
#include <cmath>
#include <iostream>
#include <map>
#include <numeric>
#include <queue>
#include <set>
#include <stack>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <string>
#include <time.h>
#include <vector>
#define Endl endl
#define mp make_pair
#define ll long long
#define ull unsigned long long
#define pii pair<int, int>
#define over(A)                                                                \\
  {                                                                            \\
    cout << A << endl;                                                         \\
    exit(0);                                                                   \\
  }
#define all(A) A.begin(), A.end()
#define quickcin ios_base::sync_with_stdio(false);
const int mod = 998244353;
const int gmod = 2;
const int inf = 1039074182;
const ll llinf = 1LL * inf * inf;
template <typename T1, typename T2> inline void chmin(T1 &x, T2 b) {
  if (b < x)
    x = b;
}
template <typename T1, typename T2> inline void chmax(T1 &x, T2 b) {
  if (b > x)
    x = b;
}
template <typename T1, typename T2> inline void chadd(T1 &x, T2 b) {
  x += b;
  if (x >= mod)
    x -= mod;
}
template <typename T1, typename T2> inline void chmul(T1 &x, T2 b) {
  x = 1LL * x * b % mod;
}
template <typename T1, typename T2> inline void chmod(T1 &x, T2 b) {
  x %= b, x += b;
  if (x >= b)
    x -= b;
}
#endif

#ifndef _SELF_DEBUG
#define _SELF_DEBUG 1
#ifndef _SELF_OPERATOR
#define _SELF_OPERATOR 1
using namespace std;
template <typename T> ostream &operator<<(ostream &cout, vector<T> vec) {
  cout << "{";
  for (int i = 0; i < (int)vec.size(); i++) {
    cout << vec[i];
    if (i != (int)vec.size() - 1)
      cout << ',';
  }
  cout << "}";
  return cout;
}

template <typename T1, typename T2>
ostream &operator<<(ostream &cout, pair<T1, T2> p) {
  cout << "(" << p.first << ',' << p.second << ")";
  return cout;
}

template <typename T, typename T2>
ostream &operator<<(ostream &cout, set<T, T2> s) {
  vector<T> t;
  for (auto x : s)
    t.push_back(x);
  cout << t;
  return cout;
}

template <typename T> ostream &operator<<(ostream &cout, multiset<T> s) {
  vector<T> t;
  for (auto x : s)
    t.push_back(x);
  cout << t;
  return cout;
}

template <typename T> ostream &operator<<(ostream &cout, queue<T> q) {
  vector<T> t;
  while (q.size()) {
    t.push_back(q.front());
    q.pop();
  }
  cout << t;
  return cout;
}

template <typename T1, typename T2>
ostream &operator<<(ostream &cout, map<T1, T2> m) {
  for (auto &x : m) {
    cout << "Key: " << x.first << ' ' << "Value: " << x.second << endl;
  }
  return cout;
}

template <typename T> T operator*(vector<T> v1, vector<T> v2) {
  assert(v1.size() == v2.size());
  int n = v1.size();
  T res = 0;
  for (int i = 0; i < n; i++) {
    res += v1[i] * v2[i];
  }
  return res;
}

template <typename T1, typename T2>
pair<T1, T2> operator+(pair<T1, T2> x, pair<T1, T2> y) {
  return make_pair(x.first + y.first, x.second + y.second);
}

template <typename T1, typename T2>
void operator+=(pair<T1, T2> &x, pair<T1, T2> y) {
  x.first += y.first;
  x.second += y.second;
}

template <typename T1, typename T2> pair<T1, T2> operator-(pair<T1, T2> x) {
  return make_pair(-x.first, -x.second);
}

template <typename T> vector<vector<T>> operator~(vector<vector<T>> vec) {
  vector<vector<T>> v;
  int n = vec.size(), m = vec[0].size();
  v.resize(m);
  for (int i = 0; i < m; i++) {
    v[i].resize(n);
  }
  for (int i = 0; i < m; i++) {
    for (int j = 0; j < n; j++) {
      v[i][j] = vec[j][i];
    }
  }
  return v;
}
#endif

void print0x(int x) {
  std::vector<int> vec;
  while (x) {
    vec.push_back(x & 1);
    x >>= 1;
  }
  std::reverse(vec.begin(), vec.end());
  for (int i = 0; i < (int)vec.size(); i++) {
    std::cout << vec[i];
  }
  std::cout << ' ';
}

template <typename T> void print0x(T x, int len) {
  std::vector<int> vec;
  while (x) {
    vec.push_back(x & 1);
    x >>= 1;
  }
  reverse(vec.begin(), vec.end());
  for (int i = vec.size(); i < len; i++) {
    putchar('0');
  }
  for (int i = 0; i < vec.size(); i++) {
    std::cout << vec[i];
  }
  std::cout << ' ';
}
#endif

struct NetworkWithCost {
  struct Edge {
    int vertex;
    int flow;
    int cost;
    int inv;
  };
  vector<Edge> *edges;
  inline void addEdge(int x, int y, int limit, int cost) {
    Edge edge;
    edge.cost = cost;
    edge.flow = limit;
    edge.vertex = y;
    edge.inv = (int)edges[y].size();
    edges[x].push_back(edge);
    edge.vertex = x;
    edge.flow = 0;
    edge.cost = -cost;
    edge.inv = (int)edges[x].size() - 1;
    edges[y].push_back(edge);
  }
  int src, dst;
  int n;
  void init(int _n) {
    n = _n;
    edges = new vector<Edge>[n];
    src = dst = -1;
  }
  void feedsd(int _src, int _dst) {
    src = _src;
    dst = _dst;
  }
  void clear() {
    for (int i = 0; i < n; i++) {
      edges[i].clear();
    }
    src = dst = -1;
  }
};

namespace MCMFSpace {
void operator+=(pii &a, const pii &b) {
  a.first += b.first;
  a.second += b.second;
}
} // namespace MCMFSpace

struct MCMF {
  const int DistInf = 1039074182;
  NetworkWithCost g;
  int *dist;
  bool *visit;
  int *cur;
  queue<int> que;
  inline void init(NetworkWithCost &_g) {
    g = _g;
    dist = new int[g.n + 5];
    visit = new bool[g.n + 5];
    cur = new int[g.n + 5];
  }

  bool bellmanford() {
    //	cout<<"Bf started";
    for (int i = 0; i < g.n; i++) {
      dist[i] = inf;
    }
    dist[g.src] = 0;
    int changeCommitted;
    for (int T = 0; T < g.n; T++) {
      changeCommitted = 0;
      for (int i = 0; i < g.n; i++) {
        if (dist[i] == inf)
          continue;
        for (auto &e : g.edges[i]) {
          if (e.flow == 0)
            continue;
          if (dist[e.vertex] > dist[i] + e.cost) {
            dist[e.vertex] = dist[i] + e.cost;
            changeCommitted = true;
          }
        }
      }
      if (!changeCommitted)
        break;
    }
    //	system("pause");
    return (dist[g.dst] < inf);
  }

  bool dijkstra() {
    for (int i = 0; i < g.n; i++) {
      dist[i] = -1;
    }
    dist[g.src] = 0;
    priority_queue<pii, vector<pii>, greater<pii>> pq;
    pq.push(mp(0, 0));
    while (pq.size()) {
      int x = pq.top().second;
      int cost = pq.top().first;
      pq.pop();
      if (dist[x] != cost)
        continue;
      for (auto &e : g.edges[x]) {
        if (e.flow == 0)
          continue;
        if (dist[e.vertex] > cost + e.cost || dist[e.vertex] == -1) {
          dist[e.vertex] = cost + e.cost;
          pq.push(mp(dist[e.vertex], e.vertex));
        }
      }
    }
    return (dist[g.dst] != -1);
  }

  pair<int, int> dfs(int x, int flow) {
    if (x == g.dst)
      return mp(flow, 0);
    visit[x] = 1;
    pii res = {0, 0};
    for (int &i = cur[x]; i < (int)g.edges[x].size(); i++) {
      int u = g.edges[x][i].vertex;
      int c = g.edges[x][i].cost;
      if (visit[u])
        continue;
      if (dist[u] != dist[x] + c)
        continue;
      if (g.edges[x][i].flow == 0)
        continue;
      pii f = dfs(u, min(flow, g.edges[x][i].flow));
      flow -= f.first;
      res += f;
      res.second += g.edges[x][i].cost * f.first;
      g.edges[x][i].flow -= f.first;
      g.edges[u][g.edges[x][i].inv].flow += f.first;
      if (flow == 0)
        break;
    }
    visit[x] = 0;
    return res;
  }

  pii run() {
    pair<int, int> x = mp(0, 0);
    for (int i = 0; i < g.n; i++) {
      visit[i] = 0;
    }
    while (bellmanford()) {
      //			cout<<g.n<<endl;
      //			for(int i=0;i<g.n;i++)
      //			{
      //				cout<<dist[i]<<' ';
      //			}
      //			cout<<endl;
      //			Sleep(1000);
      for (int i = 0; i < g.n; i++) {
        assert(visit[i] == 0);
      }
      for (int i = 0; i < g.n; i++) {
        cur[i] = 0;
      }
      pair<int, int> f = dfs(g.src, inf);
      //			cout<<"flow="<<f<<endl;
      x += f;
    }
    return x;
  }
};
using namespace std;
int n, m;
char c[55][55];
const int dx[] = {0, 1};
const int dy[] = {1, 0};
int dist[55][55];
int id[55][55];
int rhsNum;
vector<pii> vec[105];

inline bool out(int x, int y) { return (x >= n || y >= m); }

inline int getID(int x, int y) {
  return (id[x][y] == -1 ? id[x][y] = rhsNum++ : id[x][y]);
}

inline void bfs(int sx, int sy, int id) {
  queue<tuple<int, int>> que;
  que.push(make_tuple(sx, sy));
  for (int i = 0; i < n; i++) {
    for (int j = 0; j < m; j++) {
      dist[i][j] = -inf;
    }
  }
  //	memset(dist,-1,sizeof(dist));
  dist[sx][sy] = 0;
  while (que.size()) {
    int x, y;
    tie(x, y) = que.front();
    que.pop();
    for (int i = 0; i < 2; i++) {
      int nx = x + dx[i];
      int ny = y + dy[i];
      if (out(nx, ny) || dist[nx][ny] != -inf || c[nx][ny] == '#')
        continue;
      dist[nx][ny] = dist[x][y] + 1;
      que.push(make_tuple(nx, ny));
    }
  }
  vector<tuple<int, int, int>> vSort;
  for (int i = 0; i < n; i++) {
    for (int j = 0; j < n; j++) {
      vSort.push_back(make_tuple(dist[i][j], i, j));
    }
  }
  sort(all(vSort));
  reverse(all(vSort));
  for (int i = 0; i < min(100, (int)vSort.size()); i++) {
    vec[id].push_back(
        mp(getID(get<1>(vSort[i]), get<2>(vSort[i])), get<0>(vSort[i])));
  }
}

int main() {
  //	freopen("input.txt","r",stdin);
  memset(id, -1, sizeof(id));
  cin >> n >> m;
  for (int i = 0; i < n; i++) {
    scanf("%s", c[i]);
  }
  NetworkWithCost g;
  g.init(n * m + 2);
  int src = n * m, dst = src + 1;
  g.feedsd(src, dst);
  for (int i = 0; i < n; i++) {
    for (int j = 0; j < m; j++) {
      if (c[i][j] == '#')
        continue;
      if (!out(i + 1, j) && c[i + 1][j] != '#') {
        g.addEdge(i * m + j, (i + 1) * m + j, inf, 0);
      }
      if (!out(i, j + 1) && c[i][j + 1] != '#') {
        g.addEdge(i * m + j, (i)*m + (j + 1), inf, 0);
      }
      if (c[i][j] == 'o')
        g.addEdge(src, i * m + j, 1, i + j);
      g.addEdge(i * m + j, dst, 1, -i - j);
    }
  }
  MCMF d;
  d.init(g);
  cout << -d.run().second << endl;
  return 0;
}


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

#define rep(i, a, b) for (int i = (a), i##end = (b); i <= i##end; ++i)
#define per(i, a, b) for (int i = (a), i##end = (b); i >= i##end; --i)

mt19937 Rnd(chrono::high_resolution_clock::now().time_since_epoch().count());

template <typename T> inline void chkmax(T &x, T y) {
  if (x < y)
    x = y;
}

template <typename T> inline void chkmin(T &x, T y) {
  if (x > y)
    x = y;
}

inline int read() {
#define nc getchar()
  int x = 0;
  char c = nc;
  while (c < 48)
    c = nc;
  while (c > 47)
    x = x * 10 + (c ^ 48), c = nc;
  return x;
#undef nc
}

typedef long long ll;
typedef pair<int, int> pii;
int N, M;
char A[55][55];

bool pd(int x, int y) { return x <= N && y <= M && A[x][y] != '#'; }

int id(int x, int y) { return (x - 1) * M + y; }

int dis[55][55];
vector<pii> vec;

void dfs(int x, int y, int d) {
  if (!pd(x, y))
    return;
  dis[x][y] = d;
  vec.push_back(pii(x, y));
  dfs(x + 1, y, d + 1), dfs(x, y + 1, d + 1);
}

namespace Flow {
const int maxn = 10010, maxm = 1e7 + 10, inf = 1 << 30;
bool vis[maxn];
int S, T, h[maxn], f[maxn], dis[maxn], pre[maxn];

struct edges {
  int nxt, to, w, c;
  edges(int _n = 0, int _t = 0, int _w = 0, int _c = 0)
      : nxt(_n), to(_t), w(_w), c(_c) {}
} e[maxm];

queue<int> q;

void addline(int u, int v, int w, int c) {
  //  printf("(%d %d) %d %d\\n", u, v, w, c);
  static int cnt = 1;
  e[++cnt] = edges(h[u], v, w, c), h[u] = cnt;
  e[++cnt] = edges(h[v], u, 0, -c), h[v] = cnt;
}

bool bfs() {
  memset(dis, 0x3f, (T + 1) << 2);
  q.push(S), dis[S] = 0, f[S] = inf;
  while (!q.empty()) {
    int u = q.front();
    vis[u] = 0, q.pop();
    for (int i = h[u]; i; i = e[i].nxt) {
      int v = e[i].to;
      if (e[i].w && dis[u] + e[i].c < dis[v]) {
        pre[v] = i;
        f[v] = min(f[u], e[i].w);
        dis[v] = dis[u] + e[i].c;
        if (!vis[v])
          q.push(v), vis[v] = 1;
      }
    }
  }
  return dis[T] < 1e9;
}

int EK() {
  int res = 0;
  //  int tmp = 0;
  while (bfs()) {
    res += f[T] * dis[T];
    //    tmp += f[T];
    for (int u = T; u != S; u = e[pre[u] ^ 1].to) {
      e[pre[u]].w -= f[T], e[pre[u] ^ 1].w += f[T];
    }
  }
  //  printf("#%d\\n", tmp);
  return res;
}
} // namespace Flow

void solve() {
  cin >> N >> M;
  rep(i, 1, N) { scanf("%s", A[i] + 1); }
  Flow::S = N * M * 2 + 1, Flow::T = N * M * 2 + 2;
  rep(i, 1, N) rep(j, 1, M) Flow::addline(N * M + id(i, j), Flow::T, 1, 0);
  rep(i, 1, N) rep(j, 1, M) if (A[i][j] == 'o') {
    Flow::addline(Flow::S, id(i, j), 1, 0);
    vec.clear();
    dfs(i, j, 0);
    for (pii p : vec) {
      Flow::addline(id(i, j), N * M + id(p.first, p.second), 1,
                    -dis[p.first][p.second]);
    }
  }
  cout << -Flow::EK() << endl;
}

signed main() {
  //  int T = read();
  //  while (T--) solve();
  solve();
  return 0;
}

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

#define rep(i, a, b) for (int i = (a), i##end = (b); i <= i##end; ++i)
#define per(i, a, b) for (int i = (a), i##end = (b); i >= i##end; --i)

mt19937 Rnd(chrono::high_resolution_clock::now().time_since_epoch().count());

template <typename T> inline void chkmax(T &x, T y) {
  if (x < y)
    x = y;
}

template <typename T> inline void chkmin(T &x, T y) {
  if (x > y)
    x = y;
}

inline int read() {
#define nc getchar()
  int x = 0;
  char c = nc;
  while (c < 48)
    c = nc;
  while (c > 47)
    x = x * 10 + (c ^ 48), c = nc;
  return x;
#undef nc
}

typedef long long ll;
typedef pair<int, int> pii;
int N, M;
char A[55][55];

bool pd(int x, int y) { return x <= N && y <= M && A[x][y] != '#'; }

int id(int x, int y) { return (x - 1) * M + y; }

int dis[55][55];
vector<pii> vec;

void dfs(int x, int y, int d) {
  if (!pd(x, y) || dis[x][y] != -1)
    return;
  dis[x][y] = d;
  vec.push_back(pii(x, y));
  dfs(x + 1, y, d + 1), dfs(x, y + 1, d + 1);
}

namespace Flow {
const int maxn = 10010, maxm = 2e6 + 10, inf = 1 << 30;
bool vis[maxn];
int S, T, h[maxn], f[maxn], dis[maxn], pre[maxn];

struct edges {
  int nxt, to, w, c;
  edges(int _n = 0, int _t = 0, int _w = 0, int _c = 0)
      : nxt(_n), to(_t), w(_w), c(_c) {}
} e[maxm];

queue<int> q;

void addline(int u, int v, int w, int c) {
  //  printf("(%d %d) %d %d\\n", u, v, w, c);
  static int cnt = 1;
  e[++cnt] = edges(h[u], v, w, c), h[u] = cnt;
  e[++cnt] = edges(h[v], u, 0, -c), h[v] = cnt;
}

bool bfs() {
  memset(dis, 0x3f, (T + 1) << 2);
  q.push(S), dis[S] = 0, f[S] = inf;
  while (!q.empty()) {
    int u = q.front();
    vis[u] = 0, q.pop();
    for (int i = h[u]; i; i = e[i].nxt) {
      int v = e[i].to;
      if (e[i].w && dis[u] + e[i].c < dis[v]) {
        pre[v] = i;
        f[v] = min(f[u], e[i].w);
        dis[v] = dis[u] + e[i].c;
        if (!vis[v])
          q.push(v), vis[v] = 1;
      }
    }
  }
  return dis[T] < 1e9;
}

int EK() {
  int res = 0;
  //  int tmp = 0;
  while (bfs()) {
    res += f[T] * dis[T];
    //    tmp += f[T];
    for (int u = T; u != S; u = e[pre[u] ^ 1].to) {
      e[pre[u]].w -= f[T], e[pre[u] ^ 1].w += f[T];
    }
  }
  //  printf("#%d\\n", tmp);
  return res;
}
} // namespace Flow

void solve() {
  cin >> N >> M;
  rep(i, 1, N) { scanf("%s", A[i] + 1); }
  Flow::S = N * M * 2 + 1, Flow::T = N * M * 2 + 2;
  rep(i, 1, N) rep(j, 1, M) Flow::addline(N * M + id(i, j), Flow::T, 1, 0);
  rep(i, 1, N) rep(j, 1, M) if (A[i][j] == 'o') {
    Flow::addline(Flow::S, id(i, j), 1, 0);
    vec.clear();
    memset(dis, -1, sizeof dis);
    dfs(i, j, 0);
    for (pii p : vec) {
      Flow::addline(id(i, j), N * M + id(p.first, p.second), 1,
                    -dis[p.first][p.second]);
    }
  }
  cout << -Flow::EK() << endl;
}

signed main() {
  //  int T = read();
  //  while (T--) solve();
  solve();
  return 0;
}


#include <bits/stdc++.h>
using namespace std;
int main() {
  string s;
  cin >> s;
  int l = s.length();
  if (s[l - 1] == 's') {
    s.erase(l - 2, 1);
    s.append("es");
  } else {
    s.append("s");
  }
  cout << s << endl;

  return 0;
}

#include <bits/stdc++.h>
using namespace std;
int main() {
  std::string s;
  cin >> s;
  int l = s.length();
  if (s[l - 1] == 's') {
    s.append("es");
  } else {
    s.append("s");
  }
  cout << s << endl;

  return 0;
}


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

int main() {
  string X;
  cin >> X;
  if (X.at(-1) == 's') {
    cout << X << "es" << endl;
  } else {
    cout << X << "s" << endl;
  }
}

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

int main() {
  string X;
  cin >> X;
  char a = X[X.size() - 1];

  if (a == 's') {
    cout << X << "es" << endl;
  } else {
    cout << X << "s" << endl;
  }
}

terminate called after throwing an instance of 'std::out_of_range'
  what():  basic_string::at: __n (which is 18446744073709551615) >= this->size() (which is 5)


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

using ll = long long;

#define pb push_back
#define ff first
#define ss second
#define all(a) a.begin(), a.end()
#define sz(a) (int)(a.size())
#define clr(a, b) memset(a, b, sizeof(a))
#define REP(i, a, b) for (int i = (int)(a); i < (int)(b); ++i)
#define REPD(i, a, b) for (int i = (int)(a)-1; i >= (int)(b); --i)

template <typename T> inline bool chkmin(T &a, const T &b) {
  return a > b ? a = b, 1 : 0;
}
template <typename T> inline bool chkmax(T &a, const T &b) {
  return a < b ? a = b, 1 : 0;
}

mt19937 rng(chrono::steady_clock::now().time_since_epoch().count());

const int NX = 1e5 + 5;
int N, a[NX];
ll M;

ll gcd(ll aa, ll b) {
  if (aa == 0 || b == 0)
    return max(aa, b);
  return gcd(b % aa, aa);
}

ll lcm(ll aa, ll b) { return 1ll * aa * b / gcd(aa, b); }

int main() {
  ios_base::sync_with_stdio(false);
  cin.tie(NULL);
  cin >> N >> M;
  ll l = 1;
  REP(i, 0, N) {
    cin >> a[i];
    l = lcm(l, a[i]);
  }
  REP(i, 0, N) {
    if (l / a[i] % 2 == 0) {
      cout << 0 << "\\n";
      return 0;
    }
  }
  l /= 2;
  cout << M / l / 2 + M / l % 2 << "\\n";
  return 0;
}

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

using ll = long long;

#define pb push_back
#define ff first
#define ss second
#define all(a) a.begin(), a.end()
#define sz(a) (int)(a.size())
#define clr(a, b) memset(a, b, sizeof(a))
#define REP(i, a, b) for (int i = (int)(a); i < (int)(b); ++i)
#define REPD(i, a, b) for (int i = (int)(a)-1; i >= (int)(b); --i)

template <typename T> inline bool chkmin(T &a, const T &b) {
  return a > b ? a = b, 1 : 0;
}
template <typename T> inline bool chkmax(T &a, const T &b) {
  return a < b ? a = b, 1 : 0;
}

mt19937 rng(chrono::steady_clock::now().time_since_epoch().count());

int main() {
  ios_base::sync_with_stdio(false);
  cin.tie(NULL);
  string s;
  cin >> s;
  if (s.back() == 's')
    s += "es";
  else
    s += 's';
  cout << s << endl;
  return 0;
}


#include <iostream>
#include <string>
using namespace std;
int main() {
  int i;
  string str;
  cin >> str;
  int str1 = str.size();
  if (str.at(str1) == 's') {
    cout << str + "es" << endl;
  } else {
    cout << str + "s" << endl;
  }
}

#include <iostream>
#include <string>
using namespace std;
int main() {
  int i;
  string str;
  cin >> str;
  int str1 = str.size();
  if (str.at(str1 - 1) == 's') {
    cout << str + "es" << endl;
  } else {
    cout << str + "s" << endl;
  }
}

terminate called after throwing an instance of 'std::out_of_range'
  what():  basic_string::at: __n (which is 5) >= this->size() (which is 5)


#include <bits/stdc++.h>
using namespace std;
int main() {
  string s, c;
  cin >> s;
  c = s;
  if (s[s.length() - 1] != 's')
    c += "s";
  else {
    c.erase(c.end());
    c += "es";
  }
  cout << c;
  return 0;
}

#include <bits/stdc++.h>
using namespace std;
int main() {
  string s, c;
  cin >> s;
  c = s;
  if (s[s.length() - 1] != 's')
    c += "s";
  else {
    c += "es";
  }
  cout << c;
  return 0;
}


#include <algorithm>
#include <array>
#include <bitset>
#include <cassert>
#include <cctype>
#include <chrono>
#include <cmath>
#include <complex>
#include <cstdint>
#include <cstdlib>
#include <cstring>
#include <ctime>
#include <deque>
#include <fstream>
#include <functional>
#include <iomanip>
#include <iostream>
#include <list>
#include <map>
#include <numeric>
#include <queue>
#include <random>
#include <set>
#include <sstream>
#include <stack>
#include <stdio.h>
#include <string>
#include <tuple>
#include <unistd.h>
#include <unordered_map>
#include <unordered_set>
#include <vector>
using namespace std;

typedef long double ld;
typedef long long ll;
typedef unsigned long long ull;
typedef pair<int, int> pii;
typedef pair<ll, ll> pll;
typedef pair<double, double> pdd;

#define mp make_pair
#define pb push_back
#define f first
#define s second
#define fast_work                                                              \\
  {                                                                            \\
    ios_base::sync_with_stdio(0);                                              \\
    cin.tie(0);                                                                \\
    cout.tie(0);                                                               \\
  }

const ll INF = 1e18 + 5, NMAX = 1e6 + 5, MOD = 1000000007, N = 1e9 + 5,
         LOG = 25;
const ld EPS = 1e-8, pi = 3.14159265358979323846;

signed solve() {
  string s;
  cin >> s;

  if (s.back() == 's')
    s += "es";
  else
    s += "s";

  cout << s;
}

signed main() {
  fast_work

      int t = 1;
  // cin >> t;

  while (t-- > 0)
    solve();
}

#include <algorithm>
#include <array>
#include <bitset>
#include <cassert>
#include <cctype>
#include <chrono>
#include <cmath>
#include <complex>
#include <cstdint>
#include <cstdlib>
#include <cstring>
#include <ctime>
#include <deque>
#include <fstream>
#include <functional>
#include <iomanip>
#include <iostream>
#include <list>
#include <map>
#include <numeric>
#include <queue>
#include <random>
#include <set>
#include <sstream>
#include <stack>
#include <stdio.h>
#include <string>
#include <tuple>
#include <unistd.h>
#include <unordered_map>
#include <unordered_set>
#include <vector>
using namespace std;

typedef long double ld;
typedef long long ll;
typedef unsigned long long ull;
typedef pair<int, int> pii;
typedef pair<ll, ll> pll;
typedef pair<double, double> pdd;

#define mp make_pair
#define pb push_back
#define f first
#define s second
#define fast_work                                                              \\
  {                                                                            \\
    ios_base::sync_with_stdio(0);                                              \\
    cin.tie(0);                                                                \\
    cout.tie(0);                                                               \\
  }

const ll INF = 1e18 + 5, NMAX = 1e6 + 5, MOD = 1000000007, N = 1e9 + 5,
         LOG = 25;
const ld EPS = 1e-8, pi = 3.14159265358979323846;

signed main() {
  fast_work

      string s;
  cin >> s;

  if (s.back() == 's')
    s += "es";
  else
    s += "s";

  cout << s;
}


#include <iostream>
#include <string>
using namespace std;
int main() {
  string a;
  string d = "es", e = "s";
  int b = a.size();
  char c = a.at(b - 1);
  if (c == 's')
    cout << a + d;
  else
    cout << a + e;

  return 0;
}

#include <iostream>
#include <string>
using namespace std;
int main() {
  string a;
  cin >> a;
  string d = "es", e = "s";
  int b = a.size();
  char c = a.at(b - 1);
  if (c == 's')
    cout << a + d;
  else
    cout << a + e;

  return 0;
}

terminate called after throwing an instance of 'std::out_of_range'
  what():  basic_string::at: __n (which is 18446744073709551615) >= this->size() (which is 0)


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

int main() {
  string word;
  cin >> word;

  if (word.at(word.size() - 1) == 's') {
    word.at(word.size()) = 'e';
    word.at(word.size()) = 's';
  } else {
    word.at(word.size()) = 's';
  }
  cout << word << endl;
}

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

int main() {
  string word, answer;
  cin >> word;

  if (word.at(word.size() - 1) == 's') {
    answer = word + "es";
  } else {
    answer = word + 's';
  }
  cout << answer << endl;
}


#include <bits/stdc++.h>
using namespace std;
int main() {
  int i;
  string s;
  cin >> s;
  for (i = 0; i < s.length(); i++) {
    if (s[s.length() - 1] == 's') {
      s.push_back('e');
      s.push_back('s');
    } else
      s.push_back('s');
  }
  cout << s;
}

#include <bits/stdc++.h>

using namespace std;

int main() {
  int n;
  string s;
  cin >> s;
  n = s.size();
  if (s[n - 1] == 's')
    cout << s << "es" << endl;
  else
    cout << s << "s" << endl;

  return 0;
}


#include <iostream>
#include <string>
using namespace std;

int main() {
  string s;
  if (s.at(s.size() - 1) == 's') {
    cout << s << "es";
  } else {
    cout << s << "s";
  }
}

#include <iostream>
#include <string>
using namespace std;

int main() {
  string s;
  int a;
  cin >> s;
  a = s.size();
  if (s.at(a - 1) == 's') {
    cout << s << "es";
  } else {
    cout << s << "s";
  }
}


#include <algorithm>
#include <cstdio>
#include <cstring>
using namespace std;
int main(void) {
  char s[103];
  int i, len, k = 0;
  scanf("%s", s);
  len = strlen(s);
  if (s[len - 1] == 's') {
    s[len] = 'e';
    s[len + 1] = 's';
    k = 1;
  } else
    s[len] = 's';
  if (k == 1) {
    for (i = 0; i < len + 2; i++)
      printf("%c", s[i]);
  } else {
    for (i = 0; i <= len; i++)
      printf("%c", s[i]);
  }
  return 0;
}

#include <algorithm>
#include <cstdio>
#include <cstring>
using namespace std;
int main(void) {
  char s[1003];
  int i, len, k = 0;
  scanf("%s", s);
  len = strlen(s);
  if (s[len - 1] == 's') {
    s[len] = 'e';
    s[len + 1] = 's';
    k = 1;
  } else
    s[len] = 's';
  if (k == 1) {
    for (i = 0; i < len + 2; i++)
      printf("%c", s[i]);
  } else {
    for (i = 0; i <= len; i++)
      printf("%c", s[i]);
  }
  return 0;
}


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

int main() {
  string str;
  if (str.at(str.size() - 1) == 's')
    cout << str + "es" << endl;
  else
    cout << str + 's' << endl;
}

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

int main() {
  string str;
  cin >> str;
  if (str.at(str.size() - 1) == 's')
    cout << str + "es" << endl;
  else
    cout << str + 's' << endl;
}


#include <iostream>
#include <string.h>
using namespace std;
int main() {
  char w[1000];
  cin >> w;
  int l = strlen(w);
  if (w[l - 1] == 's') {
    char p[l + 1];
    w[l] = 'e';
    w[l + 1] = 's';
    strcpy(p, w);
    for (int i = 0; i <= l + 1; i++) {
      cout << p[i];
    }
  }

  else {
    w[l] = 's';
    char p[l];
    strcpy(p, w);
    for (int i = 0; i <= l; i++) {
      cout << p[i];
    }
  }
}

#include <iostream>
#include <string.h>
using namespace std;
int main() {
  char w[1000];
  cin >> w;
  int l = strlen(w);
  if (w[l - 1] == 's')
    cout << w << "es";
  else
    cout << w << 's';
}


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

int main() {
  string takahashi;
  cin >> takahashi;
  if (takahashi.at(takahashi.size()) == 's') {
    takahashi += "es";
  } else {
    takahashi += "s";
  }
}

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

int main() {
  string takahashi;
  cin >> takahashi;
  if (takahashi.at(takahashi.size() - 1) == 's') {
    takahashi += "es";
  } else {
    takahashi += "s";
  }

  cout << takahashi << endl;
}


#pragma warning(disable : 4996)
#include <iostream>
#include <stdio.h>
#include <string.h>
using namespace std;
#define MAX 1001

char str[MAX];

int main() {
  scanf("%s", str);
  for (int i = 0; str[i] != '\\0'; i++) {
    if (str[i + 1] == '\\0') {
      if (str[i] == 's')
        strcat(str, "es");
      else
        strcat(str, "s");
      break;
    }
  }
  printf("%s", str);
}

#pragma warning(disable : 4996)
#include <iostream>
#include <stdio.h>
#include <string.h>
using namespace std;
#define MAX 1010

char str[MAX];

int main() {
  scanf("%s", str);
  for (int i = 0; str[i] != '\\0'; i++) {
    if (str[i + 1] == '\\0') {
      if (str[i] == 's')
        strcat(str, "es");
      else
        strcat(str, "s");
      break;
    }
  }
  printf("%s", str);
}


#include <bits/stdc++.h>
#define rep(i, n) for (int i = 0; i < (int)(n); i++)

using namespace std;
typedef long long ll;

int main() {
  char S[256];
  cin >> S;
  int len = strlen(S);
  if (S[len - 1] != 's')
    cout << S << "s";
  if (S[len - 1] == 's')
    cout << S << "es";
  return 0;
}

#include <bits/stdc++.h>
#define rep(i, n) for (int i = 0; i < (int)(n); i++)

using namespace std;
typedef long long ll;

int main() {
  char s[1000];
  cin >> s;
  int len = strlen(s);
  if (s[len - 1] != 's')
    cout << s << "s";
  else if (s[len - 1] == 's')
    cout << s << "es";
  return 0;
}


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

void change_to_plural(char *input_string, char *output_string) {
  int n;
  n = strlen(input_string);

  if (input_string[n - 1] == 's') {
    input_string[n] = 'e';
    input_string[n + 1] = 's';
    input_string[n + 2] = '\\0';
  } else

  {
    input_string[n] = 's';
    input_string[n + 1] = '\\0';
  }

  output_string = input_string;
  n = strlen(input_string);
  for (int i = 0; i < n; i++)
    cout << output_string[i];
}

int main() {

  char in[10], out[10];

  cin >> in;

  change_to_plural(in, out);

  cout << endl;
}

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

void change_to_plural(char *input_string, char *output_string) {
  int n;
  n = strlen(input_string);

  if (input_string[n - 1] == 's') {
    input_string[n] = 'e';
    input_string[n + 1] = 's';
    input_string[n + 2] = '\\0';
  } else

  {
    input_string[n] = 's';
    input_string[n + 1] = '\\0';
  }

  output_string = input_string;
  n = strlen(input_string);
  for (int i = 0; i < n; i++)
    cout << output_string[i];
}

int main() {

  char in[1000], out[1000];

  cin >> in;

  change_to_plural(in, out);

  cout << endl;
}


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

int main() {
  string str;
  int i;
  cin >> i >> str;

  i = str.size() - 1;

  if (str.at(i) == 's') {
    cout << str << "es" << endl;
  } else {
    cout << str << "s" << endl;
  }
}

#include <bits/stdc++.h>
using namespace std;
#define rep(i, n) for (int i = 0; (int)(n); i++)

int main() {
  string text;
  cin >> text;

  if (text.back() == 's') {
    cout << text << "es" << endl;
  } else {
    cout << text << "s" << endl;
  }
}


#include <iostream>
using namespace std;

int main() {
  char a[105];
  int i, j;
  for (i = 0;; i++) {
    cin >> a[i];
    if (a[i] == '\\n')
      break;
  }
  for (j = 0; j < i - 1; j++) {
    cout << a[j];
  }
  if (a[i] == 's') {
    cout << 'e' << 's';
  } else
    cout << 's';
}

#include <iostream>
using namespace std;
int main() {
  string a;
  cin >> a;
  int len = a.length();
  if (a[len - 1] == 's')
    cout << a << "es" << endl;
  else
    cout << a << 's' << endl;
}


#include <bits/stdc++.h>
using namespace std;
int main() {
  string s;
  scanf("%s", &s);
  if (s[s.size() - 1] == 's')
    cout << s << "es" << endl;
  else
    cout << s << 's' << endl;
  return 0;
}

#include <bits/stdc++.h>
using namespace std;
int main() {
  string s;
  cin >> s;
  if (s[s.size() - 1] == 's')
    cout << s << "es" << endl;
  else
    cout << s << 's' << endl;
  return 0;
}


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

int main() {
  string S;
  cin >> S;
  int n = 0;
  n = S.size();

  if (S.at(n) == 's') {
    cout << S + "es" << endl;
  } else {
    cout << S + 's' << endl;
  }
}

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

int main() {
  string S;
  cin >> S;
  int n = 0;
  n = S.size();

  if (S.at(n - 1) == 's') {
    cout << S + "es" << endl;
  } else {
    cout << S + 's' << endl;
  }
}


#include <iostream>
#include <string.h>
using namespace std;
int main() {
  int length;
  char str[1000];
  cin >> str;

  length = strlen(str);

  if (str[length - 1] == 's') {
    strcat(str, "es");
    cout << str;
  } else if (str[length - 1] != 's') {
    strcat(str, "s");
    cout << str;
  }
  return 0;
}


#include <iostream>
#include <string.h>

using namespace std;

int main() {
  char s[1000];
  int i = 0;
  while (s[i] != '\\0') {
    cin >> s[i];
    i++;
  }
  int l = i - 1;
  if (s[l] == 's') {
    i = 0;
    while (s[i] != '\\0') {
      cout << s[i];
    }
    cout << "es";
  } else {
    i = 0;
    while (s[i] != '\\0') {
      cout << s[i];
    }
    cout << "s";
  }
}

#include <iostream>
#include <string.h>

using namespace std;

int main() {
  char s[1000];
  int i = 0;
  cin >> s;
  int len = strlen(s);
  if (s[len - 1] == 's') {
    cout << s;
    cout << "es";
  } else {
    cout << s;
    cout << "s";
  }
}


#include <stdio.h>
#include <string.h>

int main() {
  char s[255];
  scanf("%s", s);
  if (s[strlen(s) - 1] == 's')
    printf("%ses", s);
  else
    printf("%ss", s);
  return 0;
}

#include <stdio.h>
#include <string.h>

int main() {
  char s[1005];
  scanf("%s", s);
  if (s[strlen(s) - 1] == 's')
    printf("%ses", s);
  else
    printf("%ss", s);
  return 0;
}


#include <cstring>
#include <iostream>
using namespace std;

int main() {
  char s[1000];
  cin >> s;
  char s0[] = "es";
  char s1[] = "s";

  if (s[strlen(s) - 1] == 's') {
    strcat(s, s0);
    cout << s << endl;
  } else {
    strcat(s, s1);
    cout << s << endl;
  }
}

#include <cstring>
#include <iostream>
using namespace std;

int main() {
  char s[10000];
  cin >> s;
  char s0[] = "es";
  char s1[] = "s";

  if (s[strlen(s) - 1] == 's') {
    strcat(s, s0);
    cout << s << endl;
  } else {
    strcat(s, s1);
    cout << s << endl;
  }
}


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

int main() {

  string name;
  int a, x, y;
  char b, c;

  cin >> name;
  a = name.size();

  x = a - 1;
  y = a - 2;
  b = name.at(x);
  c = name.at(y);

  if (b == 's') {

    name = name + 'e' + 's';
    cout << name << endl;

  } else {
    name = name + 's';
    cout << name << endl;
  }
  return 0;
}

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

int main() {

  string name;
  int a, x, y;
  char b;

  cin >> name;
  a = name.size();
  x = a - 1;
  y = a - 2;
  b = name.at(x);

  if (b == 's') {
    name = name + 'e' + 's';
    cout << name << endl;
  } else {
    name = name + 's';
    cout << name << endl;
  }
  return 0;
}


#include <cstring>
#include <iostream>
#include <map>
#include <math.h>
#include <vector>

typedef long long ll;
// sort(rt,rt+sizeof(rt)/sizeof(rt[0]),greater<>());
using namespace std;

#define rep(i, n) for (i = 0; i < n; i++)
int main() {
  char n[100];
  cin >> n;
  int a;
  a = (int)strlen(n);
  if (n[a - 1] == 's') {
    cout << n << "es";
    return 0;
  } else if (n[a - 1] != 's') {
    cout << n << 's';
    return 0;
  }
}

#include <cstring>
#include <iostream>
#include <map>
#include <math.h>
#include <vector>

typedef long long ll;
// sort(rt,rt+sizeof(rt)/sizeof(rt[0]),greater<>());
using namespace std;

#define rep(i, n) for (i = 0; i < n; i++)
int main() {
  char n[1001];
  cin >> n;
  int a;
  a = (int)strlen(n);
  if (n[a - 1] == 's') {
    cout << n << "es";
    return 0;
  } else if (n[a - 1] != 's') {
    cout << n << 's';
    return 0;
  }
}


#include <bits/stdc++.h>
using namespace std;
#define rep(i, n) for (int i = 0; i < (int)(n); i++)

int main() {
  string S;
  cin >> S;

  int A = S.size();

  if (S.at(A) == 'S') {
    cout << S + "es" << endl;
  } else {
    cout << S + "s" << endl;
  }
}

#include <bits/stdc++.h>
using namespace std;
#define rep(i, n) for (int i = 0; i < (int)(n); i++)

int main() {
  string S;
  cin >> S;

  int A = S.size();
  int B = A - 1;

  if (S.at(B) == 's') {
    cout << S + "es" << endl;
  } else {
    cout << S + "s" << endl;
  }
}


#include <bits/stdc++.h>
using namespace std;
#define ll long long int
#define e endl
int main() {
  ll a, b, c, t, i;
  char s[100];
  cin >> s;
  a = strlen(s);

  if (s[a - 1] == 's') {
    cout << s;
    cout << "es";
  } else {
    cout << s;
    cout << "s";
  }
}

#include <bits/stdc++.h>
using namespace std;
#define ll int
#define e endl
int main() {
  ll a, b, c, t, i;
  char s[1000];
  cin >> s;
  a = strlen(s);

  if (s[a - 1] == 's') {
    cout << s;
    cout << "es";
  } else {
    cout << s;
    cout << "s";
  }
}


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

int main() {
  string S;
  cin >> S;
  char k = 's';

  if (S.at(S.size()) == k) {
    cout << S + "es" << endl;
  }
  cout << S + "s" << endl;
}

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

int main() {
  string S;
  cin >> S;
  char k = 's';

  if (S.at(S.size() - 1) == k) {
    cout << S + "es" << endl;
  } else {
    cout << S + "s" << endl;
  }
}


#include <bits/stdc++.h>
using namespace std;
int main() {
  string S;
  cin >> S;
  int X;
  X = S.size();
  if (S.at(X) == 's') {
    cout << S + "es" << endl;
  } else if (S.at(X) != 's') {
    cout << S + "s" << endl;
  }
}

#include <bits/stdc++.h>
using namespace std;
int main() {
  string S;
  cin >> S;
  int X;
  X = S.size();
  if (S.at(X - 1) == 's') {
    cout << S + "es" << endl;
  } else if (S.at(X - 1) != 's') {
    cout << S + "s" << endl;
  }
}


#include <stdio.h>
#include <string.h>

int main() {
  char word[103];
  scanf("%[^\\n]", word);
  getchar();
  int U = strlen(word);
  if (word[U - 1] == 's') {
    printf("%ses\\n", word);
  } else {
    printf("%ss\\n", word);
  }

  return 0;
}

#include <stdio.h>
#include <string.h>

int main() {
  char word[1010];
  scanf("%[^\\n]", word);
  getchar();
  int U = strlen(word);

  if (word[U - 1] == 's') {
    printf("%ses\\n", word);
  } else {
    printf("%ss\\n", word);
  }

  return 0;
}


#include <bits/stdc++.h>
using namespace std;
#define optimize()                                                             \\
  ios_base::sync_with_stdio(0);                                                \\
  cin.tie(0);                                                                  \\
  cout.tie(0);
#define endl '\\n'
int main() {
  optimize();
  int i, j, k, n;
  cin >> n;
  long long sum = 0;
  for (i = 1; i < n; i++) {
    for (j = 1; j < n; j++) {
      for (k = 1; k < n; k++) {
        if (i * j + k == n)
          sum++;
      }
    }
  }
  cout << sum << endl;
  return 0;
}

#include <bits/stdc++.h>
using namespace std;
#define optimize()                                                             \\
  ios_base::sync_with_stdio(0);                                                \\
  cin.tie(0);                                                                  \\
  cout.tie(0);
#define endl '\\n'
int main() {
  optimize();
  int i, j;
  int n;
  cin >> n;
  long long sum = 0;
  for (i = 1; i <= n - 1; i++) {
    sum += (n - 1) / i;
  }
  cout << sum << endl;
}


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

ll count_divisor(ll N) {
  ll res = 0;
  for (ll i = 1; i * i <= N; i++) {
    if (N % i == 0) {
      res += 1;
      if (N / i != i)
        res += 1;
    }
  }
  return res;
}

int main() {
  ll N;
  cin >> N;

  ll ans = 0;

  for (ll c = 1; c <= N - 1; c++) {
    ans += count_divisor(N - c);
  }

  cout << ans << endl;

  return 0;
}

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

int main() {
  ll N;
  cin >> N;

  ll ans = 0;

  for (ll c = 1; c <= N - 1; c++) {
    ans += (N - 1) / c;
  }

  cout << ans << endl;

  return 0;
}


#include <bits/stdc++.h>
using namespace std;
#define PI (3.14159265358979323846)
#define ld long double
#define int long long
#define MOD 1000000007
#define w(x)                                                                   \\
  int x;                                                                       \\
  cin >> x;                                                                    \\
  while (x--)
#define F first
#define S second
#define PB push_back

const char nl = '\\n';
const int N = 1e4 + 5;

void solve() {

  int n;
  cin >> n;

  int ans = 0;
  for (int i = 1; i <= n - 1; i++) {
    int c = 0;
    for (int j = 1; j * j <= i; j++) {
      if (i % j == 0)
        c += 2;
      if (j * j == i)
        c--;
    }
    ans += c;
  }

  cout << ans << nl;
}

int32_t main() {

  ios_base::sync_with_stdio(false);
  cin.tie(NULL);

  int t = 1;
  // cin >> t;
  while (t--)
    solve();
}

#include <bits/stdc++.h>
using namespace std;
#define PI (3.14159265358979323846)
#define ld long double
#define int long long
#define MOD 1000000007
#define w(x)                                                                   \\
  int x;                                                                       \\
  cin >> x;                                                                    \\
  while (x--)
#define F first
#define S second
#define PB push_back

const char nl = '\\n';
const int N = 1e6 + 5;

bool vis[N] = {0};
vector<int> sev;

int no_of_fact(int n) {

  int x = 1, o = n;

  for (auto p : sev) {
    int c = 0;

    if (p * p > n)
      break;

    while (n % p == 0) {
      c++;
      n /= p;
    }
    x *= (c + 1);
  }

  if (n > 2)
    x *= 2;

  return x;
}

void solve() {

  int n;
  cin >> n;

  for (int i = 2; i < n; i++) {
    if (!vis[i]) {
      sev.PB(i);
      for (int j = i * i; j < N; j += i) {
        if (j % i == 0)
          vis[j] = 1;
      }
    }
  }

  int ans = 1;
  for (int i = 2; i <= n - 1; i++) {
    if (!vis[i])
      ans += 2;
    else
      ans += no_of_fact(i);
  }

  cout << ans << nl;
}

int32_t main() {

  ios_base::sync_with_stdio(false);
  cin.tie(NULL);

  solve();
}


#include <algorithm>
#include <cassert>
#include <iostream>
#include <list>
#include <map>
#include <queue>
#include <set>
#include <stack>
#include <stdio.h>
#include <stdlib.h>
#include <string>
#include <tuple>
#include <unordered_map>
#include <unordered_set>
#include <utility>
#include <vector>
using namespace std;
using ll = long long;
const int mod = 1e9 + 7;

#define read_int(X)                                                            \\
  ll X;                                                                        \\
  scanf("%lld\\n", &X);

#define read_two_int(X, Y)                                                     \\
  ll X, Y;                                                                     \\
  scanf("%lld %lld\\n", &X, &Y);

#define read_three_int(X, Y, Z)                                                \\
  ll X, Y, Z;                                                                  \\
  scanf("%lld %lld %lld\\n", &X, &Y, &Z);

#define read_four_int(X, Y, Z, W)                                              \\
  ll X, Y, Z, W;                                                               \\
  scanf("%lld %lld %lld %lld\\n", &X, &Y, &Z, &W);

int main() {
  ll N;
  scanf("%lld", &N);

  ll ans = 0;
  for (ll i = 1; i < N; i++) {
    for (ll j = 1; j * j <= i; j++) {
      if (i % j == 0) {
        ans++;
        if (i / j != j)
          ans++;
      }
    }
  }

  printf("%lld\\n", ans);
}

#include <algorithm>
#include <cassert>
#include <iostream>
#include <list>
#include <map>
#include <queue>
#include <set>
#include <stack>
#include <stdio.h>
#include <stdlib.h>
#include <string>
#include <tuple>
#include <unordered_map>
#include <unordered_set>
#include <utility>
#include <vector>
using namespace std;
using ll = long long;
const int mod = 1e9 + 7;

#define read_int(X)                                                            \\
  ll X;                                                                        \\
  scanf("%lld\\n", &X);

#define read_two_int(X, Y)                                                     \\
  ll X, Y;                                                                     \\
  scanf("%lld %lld\\n", &X, &Y);

#define read_three_int(X, Y, Z)                                                \\
  ll X, Y, Z;                                                                  \\
  scanf("%lld %lld %lld\\n", &X, &Y, &Z);

#define read_four_int(X, Y, Z, W)                                              \\
  ll X, Y, Z, W;                                                               \\
  scanf("%lld %lld %lld %lld\\n", &X, &Y, &Z, &W);

int main() {
  ll N;
  scanf("%lld", &N);

  ll ans = 0;
  for (ll i = 1; i < N; i++) {
    ans += N / i;
  }
  for (ll j = 1; j * j <= N; j++) {
    if (N % j == 0) {
      ans--;
      if (N / j != j)
        ans--;
    }
  }
  ans++;

  printf("%lld\\n", ans);
}


#include <bits/stdc++.h>
#include <ext/pb_ds/assoc_container.hpp>
using namespace __gnu_pbds;
using namespace std;
#define int long long
#define ld long double
#define pb push_back
#define ff first
#define ss second
#define f(i, x, n) for (int i = x; i < (int)n; ++i)
#define vpii vector<pair<int, int>>
#define vi vector<int>
#define mpii map<pair<int, int>, int>
#define mpivpii map<int, vector<pair<int, int>>>
#define pii pair<int, int>
#define all(x) x.begin(), x.end()
#define sz(x) x.size()
#define mpi map<int, int>
#define vvi vector<vector<int>>
#define vvvi vector<vvi>
ld pie = 3.141592653589;
int mod = 1e9 + 7;

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

vi pr;

int fun(int n) {
  int ret = 0;
  for (int i = 1; i * i <= n; ++i) {
    if (n % i == 0) {
      int ano = n / i;
      ret += 1 + (ano != i);
    }
  }
  return ret;
}

void solve() {
  int n;
  cin >> n;
  int cnt = 0;
  f(c, 1, n) {
    int r = n - c;
    cnt += fun(r);
  }
  cout << cnt << "\\n";
}

int32_t main() {
  ios_base::sync_with_stdio(false);
  cin.tie(NULL);
  int t = 1; // cin>>t;
  while (t--)
    solve();
  return 0;
}

#include <bits/stdc++.h>
#include <ext/pb_ds/assoc_container.hpp>
using namespace __gnu_pbds;
using namespace std;
#define int long long
#define ld long double
#define pb push_back
#define ff first
#define ss second
#define f(i, x, n) for (int i = x; i < (int)n; ++i)
#define vpii vector<pair<int, int>>
#define vi vector<int>
#define mpii map<pair<int, int>, int>
#define mpivpii map<int, vector<pair<int, int>>>
#define pii pair<int, int>
#define all(x) x.begin(), x.end()
#define sz(x) x.size()
#define mpi map<int, int>
#define vvi vector<vector<int>>
#define vvvi vector<vvi>
ld pie = 3.141592653589;
int mod = 1e9 + 7;

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

vi pr;

int fun(int n) {
  int ret = 0;
  for (int i = 1; i * i <= n; ++i) {
    if (n % i == 0) {
      int ano = n / i;
      ret += 1 + (ano != i);
    }
  }
  return ret;
}

void solve() {
  int n;
  cin >> n;
  int fre[1000006] = {0};
  for (int i = 1; i <= 1000000; ++i)
    for (int j = 1; j <= 1000000; ++j) {
      int pro = i * j;
      if (pro > 1000000)
        break;
      fre[pro]++;
    }
  int cnt = 0;
  f(c, 1, n) {
    int r = n - c;
    cnt += fre[r];
  }
  cout << cnt << "\\n";
}

int32_t main() {
  ios_base::sync_with_stdio(false);
  cin.tie(NULL);
  int t = 1; // cin>>t;
  while (t--)
    solve();
  return 0;
}


/**
 *	created: 19.09.2020 21:07:25
 **/
#include <bits/stdc++.h>
// #include <boost/multiprecision/cpp_int.hpp>
// using bint = boost::multiprecision::cpp_int;
using namespace std;
// #define endl '\\n'
#define int long long
#define rep(i, n) for (int i = 0; i < (int)(n); i++)
#define rrep(i, n) for (int i = (int)(n - 1); i >= 0; i--)
#define rep2(i, s, n) for (int i = (s); i < (int)(n); i++)
#define all(x) (x).begin(), (x).end()
#define rall(x) (x).rbegin(), (x).rend()
#define pcnt(bit) __builtin_popcountll(bit)
using ll = long long;
using P = pair<int, int>;
const long double pi = acos(-1.0);
const int MAX = 1000010;
const int INF = 1ll << 60;
const int MOD = 1000000007;
// const int MOD = 998244353;
template <typename T> inline bool chmax(T &a, T b) {
  if (a < b) {
    a = b;
    return 1;
  }
  return 0;
}
template <typename T> inline bool chmin(T &a, T b) {
  if (b < a) {
    a = b;
    return 1;
  }
  return 0;
}
inline void print(P a) { cout << a.first << " " << a.second << endl; }
template <typename T> T pow(T a, ll n) {
  T r(1);
  while (n) {
    if (n & 1)
      r *= a;
    a *= a;
    n >>= 1;
  }
  return r;
}
struct faster_io {
  faster_io() {
    cin.tie(0);
    ios_base::sync_with_stdio(false);
  }
} faster_io_;

int dp[MAX];

int f(int i) {
  int cnt = 0;
  int sk = 0;
  for (int j = 1; j * j <= i; j++) {
    if (i % j == 0) {
      cnt++;
      if (j * j == i)
        sk++;
    }
  }
  cnt *= 2;
  if (sk == 1)
    cnt--;
  return cnt;
}

signed main() {
  int n;
  cin >> n;
  dp[0] = 0;
  dp[1] = 1;
  rep2(i, 2, n + 1) dp[i] = dp[i - 1] + f(i);
  cout << dp[n - 1] << endl;
  return 0;
}

/**
 *	created: 19.09.2020 21:07:25
 **/
#include <bits/stdc++.h>
// #include <boost/multiprecision/cpp_int.hpp>
// using bint = boost::multiprecision::cpp_int;
using namespace std;
// #define endl '\\n'
#define int long long
#define rep(i, n) for (int i = 0; i < (int)(n); i++)
#define rrep(i, n) for (int i = (int)(n - 1); i >= 0; i--)
#define rep2(i, s, n) for (int i = (s); i < (int)(n); i++)
#define all(x) (x).begin(), (x).end()
#define rall(x) (x).rbegin(), (x).rend()
#define pcnt(bit) __builtin_popcountll(bit)
using ll = long long;
using P = pair<int, int>;
const long double pi = acos(-1.0);
const int MAX = 1000010;
const int INF = 1ll << 60;
const int MOD = 1000000007;
// const int MOD = 998244353;
template <typename T> inline bool chmax(T &a, T b) {
  if (a < b) {
    a = b;
    return 1;
  }
  return 0;
}
template <typename T> inline bool chmin(T &a, T b) {
  if (b < a) {
    a = b;
    return 1;
  }
  return 0;
}
inline void print(P a) { cout << a.first << " " << a.second << endl; }
template <typename T> T pow(T a, ll n) {
  T r(1);
  while (n) {
    if (n & 1)
      r *= a;
    a *= a;
    n >>= 1;
  }
  return r;
}
struct faster_io {
  faster_io() {
    cin.tie(0);
    ios_base::sync_with_stdio(false);
  }
} faster_io_;

int dp[MAX];

signed main() {
  int n;
  cin >> n;
  dp[0] = 0;
  rep2(i, 1, n + 1) {
    for (int j = i; j <= n + 1; j += i) {
      dp[j]++;
    }
  }
  rep2(i, 1, n) { dp[i] += dp[i - 1]; }
  cout << dp[n - 1] << endl;
  return 0;
}