#include <bits/stdc++.h>
#define lsb(x) (x & (-x))
#define ll long long
#define ull unsigned long long
#define Test(tt) cout << "Case #" << tt << ": "

using namespace std;

struct Edge {
    int from, to, cost, flow;
};
struct Graph
{
    vector <Edge> edges;
    vector <int> adia[2700];
    vector <int> dist;
    int S, D, n;
 
    void bellan_ford()
    {
        vector <bool> in_queue(n, 0);
        queue <int> q;
        q.push(S);
        in_queue[S] = 1;
        dist[S] = 0;
 
        while (!q.empty()) {
            int x = q.front();
            q.pop();
            in_queue[x] = 0;
            for (auto i : adia[x]) {
                if (edges[i].flow && dist[edges[i].to] > dist[x] + edges[i].cost) {
                    dist[edges[i].to] = dist[x] + edges[i].cost;
                    if (!in_queue[edges[i].to]) {
                        in_queue[edges[i].to] = 1;
                        q.push(edges[i].to);
                    }
                }
            }
        }
    }
    int recursive_mincost(int nod)
    {
        if (dist[nod] != 1e9)
            return dist[nod];
 
        for (auto i : adia[nod])
            if (edges[i].flow)
                dist[nod] = min(dist[nod], edges[i ^ 1].cost + recursive_mincost(edges[i].from));
    }
 
    bool dijkstra(vector <int> & tata)
    {
        tata = vector <int> (n, -1);
        vector <int> cost(n, 1e9);
        priority_queue <pair <int, int>> q;
        cost[S] = 0;
        q.push({ 0, S });
        while (!q.empty()) {
            int x = q.top().second;
            if (q.top().first != -cost[x]) {
                q.pop();
                continue;
            }
            q.pop();
            for (auto i : adia[x]) {
                if (edges[i].flow && cost[edges[i].to] >
                  cost[x] + dist[x] - dist[edges[i].to] + edges[i].cost) {
                    cost[edges[i].to] = cost[x] + dist[x] - dist[edges[i].to] + edges[i].cost;
                    q.push({ -cost[edges[i].to], edges[i].to });
                    tata[edges[i].to] = i;
                }
            }
        }
        for (int i(0); i < n; i++)
            dist[i] += cost[i];
        return (tata[D] != -1);
    }
 
    void add_edge(Edge x)
    {
        adia[x.from].push_back(edges.size());
        edges.push_back(x);
        adia[x.to].push_back(edges.size());
        edges.push_back({ x.to, x.from, -x.cost, 0 });
    }
 
    pair <int, int> min_cost_max_flow()
    {
        dist = vector <int> (n, 1e9);
        bellan_ford();
        //recursive_mincost(D);
        int cost(0), flow(0);
        vector <int> tata;
        while (dijkstra(tata)) {
            int minim(1e9);
            for (int i(tata[D]); i != -1; i = tata[edges[i].from])
                minim = min(minim, edges[i].flow);
            flow += minim;
            for (int i(tata[D]); i != -1; i = tata[edges[i].from]) {
                cost += minim * edges[i].cost;
                edges[i].flow -= minim;
                edges[i ^ 1].flow += minim;
            }
        }
        return { flow, cost };
    }
 
};

const int MAXN = 50;

char mat[MAXN + 1][MAXN + 1];
bool ok[MAXN + 1][MAXN + 1][MAXN + 1][MAXN + 1];

int main() {
#ifdef HOME
    ifstream cin("C.in");
    ofstream cout("C.out");
#endif
    int i, j, n, m;
    ios::sync_with_stdio(false);
    cin.tie(0), cout.tie(0);

    cin >> n >> m;
    for(i = 1; i <= n; i++) {
    	cin >> (mat[i] + 1);
    }
    int pieces = 0;
    for(i = n; i >= 1; i--) {
    	for(j = m; j >= 1; j--) {
    		if(mat[i][j] == '#') continue;

    		pieces += (mat[i][j] == 'o');
    		ok[i][j][i][j] = 1;

    		for(int l = i; l <= n; l++) {
    			for(int r = j; r <= m; r++) {
    				if(i + 1 <= l && mat[i + 1][j] != '#') {
    					ok[i][j][l][r] |= ok[i + 1][j][l][r];
    				}
    				if(j + 1 <= r && mat[i][j + 1] != '#') {
    					ok[i][j][l][r] |= ok[i][j + 1][l][r];
    				}
    			}
    		}
    	}
    }

    Graph graph;
    graph.S = pieces + n * m + 1;
    graph.D = pieces + n * m + 2;
    graph.n = graph.D + 1;

    int cur = 0;
    for(i = 1; i <= n; i++) {
    	for(j = 1; j <= m; j++) {
    		if(mat[i][j] == 'o') {
    			cur++;
    			for(int l = i; l <= n; l++) {
    				for(int r = j; r <= m; r++) {
    					if(ok[i][j][l][r]) {
    						graph.add_edge({cur, pieces + (l - 1) * m + r, 100 - (l + r - i - j), 1});
    						//cerr << i << " " << j << " " << l << " " << r << "\n";
    					}
    				}
    			}
    		}
    		graph.add_edge({(i - 1) * m + j + pieces, graph.D, 0, 1});
    	}
    }


    for(i = 1; i <= pieces; i++) {
    	graph.add_edge({graph.S, i, 0, 1});
    }

    auto ans = graph.min_cost_max_flow();
    cout << -ans.second + ans.first * 100;

    return 0;
}

Measured memory_bytes: 14684