#include <bits/stdc++.h>
using namespace std;
 
#define send {ios_base::sync_with_stdio(false);}
#define help {cin.tie(NULL); cout.tie(NULL);}
#define f first
#define s second
#define getunique(v) {sort(v.begin(), v.end()); v.erase(unique(v.begin(), v.end()), v.end());}
typedef long long ll;
typedef long double lld;
typedef unsigned long long ull;
 
template<typename A> ostream& operator<<(ostream &cout, vector<A> const &v);
template<typename A, typename B> ostream& operator<<(ostream &cout, pair<A, B> const &p) { return cout << "(" << p.f << ", " << p.s << ")"; }
template<typename A> ostream& operator<<(ostream &cout, vector<A> const &v) {
	cout << "["; for(int i = 0; i < v.size(); i++) {if (i) cout << ", "; cout << v[i];} return cout << "]";
}
template<typename A, typename B> istream& operator>>(istream& cin, pair<A, B> &p) {
	cin >> p.first;
	return cin >> p.second;
}
 
mt19937 rng(std::chrono::steady_clock::now().time_since_epoch().count());
// mt19937 rng(61378913);
/* usage - just do rng() */
 
void usaco(string filename) {
  // #pragma message("be careful, freopen may be wrong")
	freopen((filename + ".in").c_str(), "r", stdin);
	freopen((filename + ".out").c_str(), "w", stdout);
}

#include <atcoder/all>
using namespace atcoder;
 
const lld pi = 3.14159265358979323846;
// const ll mod = 1000000007;
// const ll mod = 998244353;
// ll mod;
 


ll n, m, k, q, l, r, x, y, z;
const ll template_array_size = 1e6 + 1531;
ll a[template_array_size];
ll b[template_array_size];
ll c[template_array_size];
string s, t;
ll ans = 0;

const ll dr[2] = {0, 1};
const ll dc[2] = {1, 0};
bool vis[55][55];
string ss[55];

bool valid(ll r, ll c) {
	return r < n && c < m;
}

mcf_graph<ll, ll> flow;

void bfs(ll r, ll c, ll piece) {
	queue<pair<pair<ll, ll>, ll>> q;
	
	q.push(make_pair(make_pair(r, c), 0));
	
	ll mdist = 0;
	
	while (!q.empty()) {
		pair<pair<ll, ll>, ll> x = q.front();
		
		q.pop();
		
		pair<ll, ll> p = x.f;
		
		if (vis[p.f][p.s]) continue;
		vis[p.f][p.s] = 1;
		
		mdist = max(mdist, x.s);
		
		for (ll d = 0; d < 2; d++) {
			ll nr = p.f + dr[d];
			ll nc = p.s + dc[d];
			
			if (valid(nr, nc) && ss[nr][nc] != '#') {
				q.push(make_pair(make_pair(nr, nc), x.s + 1));
			}
		}
	}
	
	q = queue<pair<pair<ll, ll>, ll>>();
	
	q.push(make_pair(make_pair(r, c), 0));
	
	memset(vis, 0, sizeof(vis));
	
	while (!q.empty()) {
		pair<pair<ll, ll>, ll> x = q.front();
		
		q.pop();
		
		pair<ll, ll> p = x.f;
		
		if (vis[p.f][p.s]) continue;
		vis[p.f][p.s] = 1;
		
		flow.add_edge(piece, 102 + p.f * m + p.s, 1, mdist - x.s);
		// cout << r << " " << c << " " << x << " " << " " << piece << " " << p.f * m + p.s + 102 << " " << mdist - x.s << '\n';
		
		for (ll d = 0; d < 2; d++) {
			ll nr = p.f + dr[d];
			ll nc = p.s + dc[d];
			
			if (valid(nr, nc) && ss[nr][nc] != '#') {
				q.push(make_pair(make_pair(nr, nc), x.s + 1));
			}
		}
	}
	
	ans += mdist;
}

void solve(int tc = 0) {
	cin >> n >> m;
	
	flow = mcf_graph<ll, ll>(102 + n * m);
	
	for (ll i = 0; i < n; i++) {
		cin >> ss[i];
	}
		
	ll ppt = 2;
	for (ll i = 0; i < n; i++) {
		for (ll j = 0; j < m; j++) {
			if (ss[i][j] == 'o') {
				memset(vis, 0, sizeof(vis));
				
				bfs(i, j, ppt);
				
				++ppt;
			}
		}
	}
	
	for (ll i = 0; i < 100; i++) flow.add_edge(0, 2 + i, 1, 0);
	for (ll i = 0; i < n * m; i++) flow.add_edge(102 + i, 1, 1, 0);
	
	pair<ll, ll> res = flow.flow(0, 1);
	// cout << res << '\n';
	cout << ans - res.s << '\n';
}
 
int main() {
	#ifdef galen_colin_local
		auto begin = std::chrono::high_resolution_clock::now();
	#endif
	
	send help
 
	#ifndef galen_colin_local
		// usaco("moop");
	#endif
	
	// usaco("cowland");
	
	// freopen("tc.cpp", "r", stdin);
 
	
	
	int tc = 1;
	// cin >> tc;
	for (int t = 0; t < tc; t++) solve(t);
	
	#ifdef galen_colin_local
		auto end = std::chrono::high_resolution_clock::now();
		cout << setprecision(4) << fixed;
		// cout << "Execution time: " << std::chrono::duration_cast<std::chrono::duration<double>>(end - begin).count() << " seconds" << endl;
	#endif
} 

Measured memory_bytes: 8772