#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <string>
#include <cmath>
#include <algorithm>
#include <iostream>
#include <queue>
#include <stack>
#include <map>
#include <set>
#include <vector>

using namespace std;

#define rep(i, l, r) for(int i=l; i<=r; i++)
#define dow(i, l, r) for(int i=l; i>=r; i--)
#define fi first
#define se second
#define pb push_back
#define mp make_pair
#define clr(x, c) memset(x,c,sizeof(x))
#define lowbit(x) (x)&(-(x))

typedef long long ll;
typedef unsigned long long ull;
typedef pair<int,int> Pii;

inline int read() {
    int x=0,f=0; char ch=getchar();
    while (ch<'0' || '9'<ch) f|=ch=='-', ch=getchar();
    while ('0'<=ch && ch<='9') x=x*10+ch-'0', ch=getchar();
    return f?-x:x;
}

#define maxn 2509
#define maxm 40009

// int s[maxn];
// inline int sum(int x) {int sum=0; while (x) sum+=s[x], x-=lowbit(x); return sum;}
// inline void add(int x) {while (x<=n) s[x]+=1, x+=lowbit(x);}

// struct edge {int x, y, c; edge *n;} e[maxm], *fir[maxn], *pt=e;
// inline void addEdge(int x, int y, int c) {
//     pt->x = x; pt->y = y; pt->c = c; pt->n = fir[x]; fir[x] = pt++;
//     pt->x = y; pt->y = x; pt->c = c; pt->n = fir[y]; fir[y] = pt++;
// }
// #define travel(x) for(edge *p=fir[x]; p; p=p->n)

// ========================== min cost network flow
int S, T, V, INF=1e9;
struct qxx {
  int nex, t, v, c;
};
qxx e[maxm];
int h[maxn], cnt = 1; // xor
void add_path(int f, int t, int v, int c) {
    e[++cnt] = (qxx){h[f], t, v, c}, h[f] = cnt;
}
void add_flow(int f, int t, int v, int c) {
    add_path(f, t, v, c);
    add_path(t, f, 0, -c);
}
int dis[maxn], pre[maxn], incf[maxn];
bool vis[maxn];
bool spfa() {
    memset(dis, 0x3f, sizeof(dis));
    queue<int> q;
    q.push(S), dis[S] = 0, incf[S] = INF, incf[T] = 0;
    while (q.size()) {
        int u = q.front();
        q.pop();
        vis[u] = 0;
        for (int i = h[u]; i; i = e[i].nex) {
            const int &v = e[i].t, &w = e[i].v, &c = e[i].c;
            if (!w || dis[v] <= dis[u] + c) continue;
            dis[v] = dis[u] + c, incf[v] = min(w, incf[u]), pre[v] = i;
            if (!vis[v]) q.push(v), vis[v] = 1;
        }
    }
    return incf[T];
}
int maxflow, mincost;
void update() {
    maxflow += incf[T];
    for (int u = T; u != S; u = e[pre[u] ^ 1].t) {
        e[pre[u]].v -= incf[T], e[pre[u] ^ 1].v += incf[T];
        mincost += incf[T] * e[pre[u]].c;
    }
}
// 调用： while(spfa())update();

// #define Q 1000000007

// inline int pow(int x, int t) {
//     int g = 1;
//     while (t) {
//         if (t&1) g = 1LL*g*x%Q;
//         x = 1LL*x*x%Q;
//         t >>= 1;
//     }
//     return g;
// }

// ll gcd(ll a, ll b){return b==0?a:gcd(b,a%b);}

// ll ex_gcd(ll a, ll b, ll &x, ll &y) {
//     if (b==0) return x=1, y=0, a; else {
//         ll d=ex_gcd(b,a%b,y,x);
//         y-=a/b*x;
//         return d;
//     }
// }

char s[55][55]; int id[55][55];

int main() {
    int n=read(), m=read();
    rep(i, 1, n) scanf("%s", s[i-1]);
    S=++V; T=++V;
    rep(i, 1, n) rep(j, 1, m) id[i][j]=++V;
    rep(i, 1, n) rep(j, 1, m) if (s[i-1][j-1]!='#') {
        if (s[i-1][j-1]=='o') add_flow(S, id[i][j], 1, 0);
        add_flow(id[i][j], T, 1, 0);
        if (i<n && s[i][j-1]!='#') add_flow(id[i][j], id[i+1][j], 109, -1);
        if (j<m && s[i-1][j]!='#') add_flow(id[i][j], id[i][j+1], 109, -1);
    }
    while(spfa()) update();
    printf("%d\n", -mincost);
    return 0;
}

Measured memory_bytes: 4052