#pragma GCC optimize("O3")

#include <iostream>
#include <algorithm>
#include <vector>
#include <queue>
#include <string>

using namespace std;
using ll = long long;

int n, m;
vector<string> a;

void read(istream& cin) {
	cin >> n >> m;
	a.resize(n);
	for (int i = 0; i < n; i++) {
		cin >> a[i];
	}
}

#define int ll
using cost_type = ll;
const cost_type COST_INF = (int)1e18;
const int FLOW_INF = (int)1e9;
struct MinCost {
	explicit MinCost(int n) {
		g.resize(n);
	}
	struct edge {
		int from, to;
		int cap;
		cost_type cost;
		int flow;
	};
	vector<edge> edges;
	vector<vector<int>> g;
	void add_edge(int from, int to, cost_type cost, int cap) {
		edge e = { from, to, cap, cost, 0 };
		g[from].push_back(edges.size());
		edges.push_back(e);
		edge e2 = { to, from, 0, -cost, 0 };
		g[to].push_back(edges.size());
		edges.push_back(e2);
	}

	pair<int, cost_type> min_cost(int n, int s, int t, bool need_max_flow, int max_flow_value = FLOW_INF) {
		cost_type cost = 0;
		int flow = 0;
		vector<cost_type> potential;
		{
			vector<int> p(n, -1);
			vector<cost_type> d(n);
			d[s] = 0;
			p[s] = s;
			bool changed = true;
			while (changed) {
				changed = false;
				for (size_t i = 0; i <
					edges.size(); ++i) {
					edge &e = edges[i];
					if (e.cap == e.flow ||
						p[e.from] == -1)
						continue;
					if (p[e.to] == -1 ||
						d[e.to] >
						d[e.from] + e.cost) {
						d[e.to] =
							d[e.from] + e.cost;
						p[e.to] = i;
						changed = true;
					}
				}
			}
			potential = std::move(d);
		}
		while (flow < max_flow_value) {
			vector<cost_type> d(n);
			vector<int> p(n, -1);
			using queue_type = pair<cost_type, int>;
			priority_queue<queue_type, vector<queue_type>, greater<queue_type>> q;
			q.push({ 0, s });
			while (!q.empty()) {
				int v = q.top().second;
				cost_type oldD = q.top().first;
				q.pop();
				if (oldD != d[v])
					continue;
				for (int id : g[v]) {
					edge &e = edges[id];
					if (e.to == s)
						continue;
					if (e.cap > e.flow) {
						cost_type newd = d[v]
							+ e.cost +
							potential[e.from]
							- potential[e.to];
						if (p[e.to] == -1 ||
							d[e.to] > newd) {
							d[e.to] = newd;
							p[e.to] = id;
							q.push({ d[e.to], e.to });
						}
					}
				}
			}
			if (p[t] == -1) {
				break;
			}
			if (d[t] + potential[t] >= 0 && !need_max_flow) {
				break;
			}
			int cur = t;
			int maxAdd = max_flow_value - flow;
			while (cur != s) {
				edge &e = edges[p[cur]];
				cur = e.from;
				maxAdd = min(maxAdd, e.cap - e.flow);
			}
			flow += maxAdd;
			cost += (potential[t] + d[t]) * maxAdd;
			cur = t;
			while (cur != s) {
				int id = p[cur];
				edges[id].flow += maxAdd;
				edges[id ^ 1].flow -= maxAdd;
				cur = edges[id].from;
			}

			for (int i = 0; i < n; ++i) {
				if (i != s && p[i] == -1) {
					potential[i] = COST_INF;
				}
				else
					potential[i] = min(potential[i]
						+ d[i], COST_INF);
			}
		}
		return make_pair(flow, cost);
	}
};

void solve(ostream& cout) {
	int p = 0;
	for (int i = 0; i < n; i++) {
		for (int j = 0; j < m; j++) {
			p += (a[i][j] == 'o');
		}
	}
	int N = p + n * m + 2;
	int S = N - 2;
	int T = N - 1;
	MinCost mc(N);
	for (int i = 0; i < p; i++) {
		mc.add_edge(S, i, 0, 1);
	}
	for (int i = 0; i < n * m; i++) {
		mc.add_edge(p + i, T, 0, 1);
	}
	for (int i = 0, id = 0; i < n; i++) {
		for (int j = 0; j < m; j++) {
			if (a[i][j] != 'o') {
				continue;
			}
			queue<pair<int, int>> q;
			q.push({ i, j });
			vector<vector<bool>> was(n, vector<bool>(m));
			was[i][j] = true;
			while (!q.empty()) {
				int ii = q.front().first;
				int jj = q.front().second;
				q.pop();
				int d = llabs(i - ii) + llabs(j - jj);
				mc.add_edge(id, p + ii * m + jj, -d, 1);
				if (ii + 1 < n && a[ii + 1][jj] != '#' && !was[ii + 1][jj]) {
					q.push({ ii + 1, jj });
					was[ii + 1][jj] = true;
				}
				if (jj + 1 < m && a[ii][jj + 1] != '#' && !was[ii][jj + 1]) {
					q.push({ ii, jj + 1 });
					was[ii][jj + 1] = true;
				}
			}
			id++;
		}
	}
	cout << -mc.min_cost(N, S, T, true).second << endl;
}

int32_t main() {
	ios::sync_with_stdio(false);
	cin.tie(nullptr);
	int T = 1;
	// cin >> T;
	while (T--) {
		read(cin);
		solve(cout);
	}
}


Measured memory_bytes: 15104