#include <queue>
#include <algorithm>
#include <iostream>
#include <map>
#include <set>
#include <cmath>
#include <iomanip>
#include <unordered_map>
#include <vector>
#include <string>

using ll = long long;

using namespace std;

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

typedef pair<ll, ll> PInt;
typedef vector<ll> VInt;
typedef vector<VInt> VVInt;
typedef vector<PInt> VPInt;

const int inf = -1e9;
VPInt hungarian(const VVInt &matrix) {
   int height = matrix.size(), width = matrix[0].size();
   VInt u(height, 0), v(width, 0);
   VInt markIndices(width, -1);
   for(int i = 0; i < height; i++) {
      VInt links(width, -1);
      VInt mins(width, inf);
      VInt visited(width, 0);
      
      int markedI = i, markedJ = -1, j;
      while(markedI != -1) {
         j = -1;
         for(int j1 = 0; j1 < width; j1++)
            if(!visited[j1]) {
               if(matrix[markedI][j1] - u[markedI] - v[j1] > mins[j1]) {
                  mins[j1] = matrix[markedI][j1] - u[markedI] - v[j1];
                  links[j1] = markedJ;
               }
               if(j==-1 || mins[j1] > mins[j])
                  j = j1;
            }
            
         int delta = mins[j];
         for(int j1 = 0; j1 < width; j1++)
            if(visited[j1]) {
               u[markIndices[j1]] += delta;
               v[j1] -= delta;
            } else {
               mins[j1] -= delta;
            }
         u[i] += delta;
         
         visited[j] = 1;
         markedJ = j;
         markedI = markIndices[j];   
      }
      
      for(; links[j] != -1; j = links[j])
         markIndices[j] = markIndices[links[j]];
      markIndices[j] = i;
   }
   
   VPInt result;
   for(int j = 0; j < width; j++)
      if(markIndices[j] != -1)
         result.push_back(PInt(markIndices[j], j));
   return result;
}
const int dpr[2] = {0, 1};
const int dpc[2] = {1, 0};

vector<vector<ll> > calc_dist(int r, int c, vector<string>& field) {
    int n = field.size();
    int m = field[0].size();
    vector<vector<ll> > dp(n, vector<ll>(m, inf));
    dp[r][c] = 0;
    queue<pair<int, int> > q;
    q.push({r, c});
    while (!q.empty()) {
        pair<int, int> cur = q.front();
        q.pop();
        for (int i = 0; i < 2; ++i) {
            int tor = cur.first + dpr[i];
            int toc = cur.second + dpc[i];
            if (tor < n && toc < m && field[tor][toc] != '#' && dp[tor][toc] == inf) {
                dp[tor][toc] = dp[cur.first][cur.second] + 1;
                q.push({tor, toc});
            }
        }
    }
    return dp;
}

void solve() {
    int n, m;
    cin >> n >> m;
    vector<string> field(n);

    vector<pair<int, int> > begins;
    for (int i = 0; i < n; ++i) {
        cin >> field[i];
        for (int j = 0; j < m; ++j) {
            if (field[i][j] == 'o') {
                begins.push_back({i, j});
            }
        }
    }

    vector<vector<ll> > matrix(begins.size(), vector<ll>(n * m, 0));

    for (int i = 0; i < begins.size(); ++i) {
        auto p = begins[i];
        auto dp = calc_dist(p.first, p.second, field);
        for (int z = 0; z < n; ++z) {
            for (int x = 0; x < m; ++x) {
                matrix[i][z * m + x] = dp[z][x];
            }
        }
    }

    auto maxp = hungarian(matrix);
    
    ll ans = 0;

    for (int i = 0; i < maxp.size(); ++i) {
        int from = maxp[i].first;
        int to = maxp[i].second;
        int from_r = begins[from].first;
        int from_c = begins[from].second;
        int to_r = to / m;
        int to_c = to % m;
        ans += (to_r - from_r) + (to_c - from_c);
    }
    cout << ans << '\n';
}

int main() {
#ifdef LOCAL
    freopen("input.txt", "r", stdin);
#endif
    solve();
}


Measured memory_bytes: 5720