Problem p02542 (C++) — buggy submission, verdict: Time Limit Exceeded

// Original Code:
// #include <self/utility>
// #include <self/debug>
// #include <self/mcmf>
// using namespace std;
// int n,m;
// char c[55][55];
// const int dx[]={0,1};
// const int dy[]={1,0};
// int dist[55][55];
// int id[55][55];
// int rhsNum;
// vector <pii> vec[105];
//
// inline bool out(int x,int y)
//{
//	return (x>=n || y>=m);
// }
//
// inline int getID(int x,int y)
//{
//	return (id[x][y]==-1?id[x][y]=rhsNum++:id[x][y]);
// }
//
// inline void bfs(int sx,int sy,int id)
//{
//	queue <tuple<int,int> > que;
//	que.push(make_tuple(sx,sy));
//	for(int i=0;i<n;i++)
//	{
//		for(int j=0;j<m;j++)
//		{
//			dist[i][j]=-inf;
//		}
//	}
////	memset(dist,-1,sizeof(dist));
//	dist[sx][sy]=0;
//	while(que.size())
//	{
//		int x,y;
//		tie(x,y)=que.front();
//		que.pop();
//		for(int i=0;i<2;i++)
//		{
//			int nx=x+dx[i];
//			int ny=y+dy[i];
//			if(out(nx,ny) || dist[nx][ny]!=-inf || c[nx][ny]=='#')
//continue; 			dist[nx][ny]=dist[x][y]+1; 			que.push(make_tuple(nx,ny));
//		}
//	}
//	vector <tuple<int,int,int> > vSort;
//	for(int i=0;i<n;i++)
//	{
//		for(int j=0;j<n;j++)
//		{
//			vSort.push_back(make_tuple(dist[i][j],i,j));
//		}
//	}
//	sort(all(vSort));
//	reverse(all(vSort));
//	for(int i=0;i<min(100,(int)vSort.size());i++)
//	{
//		vec[id].push_back(mp(getID(get<1>(vSort[i]),get<2>(vSort[i])),get<0>(vSort[i])));
//	}
//}
//
// int main()
//{
////	freopen("input.txt","r",stdin);
//	memset(id,-1,sizeof(id));
//	cin>>n>>m;
//	for(int i=0;i<n;i++)
//	{
//		scanf("%s",c[i]);
//	}
//	NetworkWithCost g;
//	g.init(n*m+2);
//	int src=n*m,dst=src+1;
//	g.feedsd(src,dst);
//	for(int i=0;i<n;i++)
//	{
//		for(int j=0;j<m;j++)
//		{
//			if(c[i][j]=='#') continue;
//			if(!out(i+1,j) && c[i+1][j]!='#')
//			{
//				g.addEdge(i*m+j,(i+1)*m+j,inf,0);
//			}
//			if(!out(i,j+1) && c[i][j+1]!='#')
//			{
//				g.addEdge(i*m+j,(i)*m+(j+1),inf,0);
//			}
//			if(c[i][j]=='o') g.addEdge(src,i*m+j,1,i+j);
//			g.addEdge(i*m+j,dst,1,-i-j);
//		}
//	}
//	MCMF d;
//	d.init(g);
//	cout<<-d.run().second<<endl;
//	return 0;
//}

// substituted with C++ Inliner
#ifndef _SELF_UTILITY
#define _SELF_UTILITY 1
#include <algorithm>
#include <assert.h>
#include <bitset>
#include <cmath>
#include <iostream>
#include <map>
#include <numeric>
#include <queue>
#include <set>
#include <stack>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <string>
#include <time.h>
#include <vector>
#define Endl endl
#define mp make_pair
#define ll long long
#define ull unsigned long long
#define pii pair<int, int>
#define over(A)                                                                \\
  {                                                                            \\
    cout << A << endl;                                                         \\
    exit(0);                                                                   \\
  }
#define all(A) A.begin(), A.end()
#define quickcin ios_base::sync_with_stdio(false);
const int mod = 998244353;
const int gmod = 2;
const int inf = 1039074182;
const ll llinf = 1LL * inf * inf;
template <typename T1, typename T2> inline void chmin(T1 &x, T2 b) {
  if (b < x)
    x = b;
}
template <typename T1, typename T2> inline void chmax(T1 &x, T2 b) {
  if (b > x)
    x = b;
}
template <typename T1, typename T2> inline void chadd(T1 &x, T2 b) {
  x += b;
  if (x >= mod)
    x -= mod;
}
template <typename T1, typename T2> inline void chmul(T1 &x, T2 b) {
  x = 1LL * x * b % mod;
}
template <typename T1, typename T2> inline void chmod(T1 &x, T2 b) {
  x %= b, x += b;
  if (x >= b)
    x -= b;
}
#endif

#ifndef _SELF_DEBUG
#define _SELF_DEBUG 1
#ifndef _SELF_OPERATOR
#define _SELF_OPERATOR 1
using namespace std;
template <typename T> ostream &operator<<(ostream &cout, vector<T> vec) {
  cout << "{";
  for (int i = 0; i < (int)vec.size(); i++) {
    cout << vec[i];
    if (i != (int)vec.size() - 1)
      cout << ',';
  }
  cout << "}";
  return cout;
}

template <typename T1, typename T2>
ostream &operator<<(ostream &cout, pair<T1, T2> p) {
  cout << "(" << p.first << ',' << p.second << ")";
  return cout;
}

template <typename T, typename T2>
ostream &operator<<(ostream &cout, set<T, T2> s) {
  vector<T> t;
  for (auto x : s)
    t.push_back(x);
  cout << t;
  return cout;
}

template <typename T> ostream &operator<<(ostream &cout, multiset<T> s) {
  vector<T> t;
  for (auto x : s)
    t.push_back(x);
  cout << t;
  return cout;
}

template <typename T> ostream &operator<<(ostream &cout, queue<T> q) {
  vector<T> t;
  while (q.size()) {
    t.push_back(q.front());
    q.pop();
  }
  cout << t;
  return cout;
}

template <typename T1, typename T2>
ostream &operator<<(ostream &cout, map<T1, T2> m) {
  for (auto &x : m) {
    cout << "Key: " << x.first << ' ' << "Value: " << x.second << endl;
  }
  return cout;
}

template <typename T> T operator*(vector<T> v1, vector<T> v2) {
  assert(v1.size() == v2.size());
  int n = v1.size();
  T res = 0;
  for (int i = 0; i < n; i++) {
    res += v1[i] * v2[i];
  }
  return res;
}

template <typename T1, typename T2>
pair<T1, T2> operator+(pair<T1, T2> x, pair<T1, T2> y) {
  return make_pair(x.first + y.first, x.second + y.second);
}

template <typename T1, typename T2>
void operator+=(pair<T1, T2> &x, pair<T1, T2> y) {
  x.first += y.first;
  x.second += y.second;
}

template <typename T1, typename T2> pair<T1, T2> operator-(pair<T1, T2> x) {
  return make_pair(-x.first, -x.second);
}

template <typename T> vector<vector<T>> operator~(vector<vector<T>> vec) {
  vector<vector<T>> v;
  int n = vec.size(), m = vec[0].size();
  v.resize(m);
  for (int i = 0; i < m; i++) {
    v[i].resize(n);
  }
  for (int i = 0; i < m; i++) {
    for (int j = 0; j < n; j++) {
      v[i][j] = vec[j][i];
    }
  }
  return v;
}
#endif

void print0x(int x) {
  std::vector<int> vec;
  while (x) {
    vec.push_back(x & 1);
    x >>= 1;
  }
  std::reverse(vec.begin(), vec.end());
  for (int i = 0; i < (int)vec.size(); i++) {
    std::cout << vec[i];
  }
  std::cout << ' ';
}

template <typename T> void print0x(T x, int len) {
  std::vector<int> vec;
  while (x) {
    vec.push_back(x & 1);
    x >>= 1;
  }
  reverse(vec.begin(), vec.end());
  for (int i = vec.size(); i < len; i++) {
    putchar('0');
  }
  for (int i = 0; i < vec.size(); i++) {
    std::cout << vec[i];
  }
  std::cout << ' ';
}
#endif

struct NetworkWithCost {
  struct Edge {
    int vertex;
    int flow;
    int cost;
    int inv;
  };
  vector<Edge> *edges;
  inline void addEdge(int x, int y, int limit, int cost) {
    Edge edge;
    edge.cost = cost;
    edge.flow = limit;
    edge.vertex = y;
    edge.inv = (int)edges[y].size();
    edges[x].push_back(edge);
    edge.vertex = x;
    edge.flow = 0;
    edge.cost = -cost;
    edge.inv = (int)edges[x].size() - 1;
    edges[y].push_back(edge);
  }
  int src, dst;
  int n;
  void init(int _n) {
    n = _n;
    edges = new vector<Edge>[n];
    src = dst = -1;
  }
  void feedsd(int _src, int _dst) {
    src = _src;
    dst = _dst;
  }
  void clear() {
    for (int i = 0; i < n; i++) {
      edges[i].clear();
    }
    src = dst = -1;
  }
};

namespace MCMFSpace {
void operator+=(pii &a, const pii &b) {
  a.first += b.first;
  a.second += b.second;
}
} // namespace MCMFSpace

struct MCMF {
  const int DistInf = 1039074182;
  NetworkWithCost g;
  int *dist;
  bool *visit;
  int *cur;
  queue<int> que;
  inline void init(NetworkWithCost &_g) {
    g = _g;
    dist = new int[g.n + 5];
    visit = new bool[g.n + 5];
    cur = new int[g.n + 5];
  }

  bool bellmanford() {
    //	cout<<"Bf started";
    for (int i = 0; i < g.n; i++) {
      dist[i] = inf;
    }
    dist[g.src] = 0;
    int changeCommitted;
    for (int T = 0; T < g.n; T++) {
      changeCommitted = 0;
      for (int i = 0; i < g.n; i++) {
        if (dist[i] == inf)
          continue;
        for (auto &e : g.edges[i]) {
          if (e.flow == 0)
            continue;
          if (dist[e.vertex] > dist[i] + e.cost) {
            dist[e.vertex] = dist[i] + e.cost;
            changeCommitted = true;
          }
        }
      }
      if (!changeCommitted)
        break;
    }
    //	system("pause");
    return (dist[g.dst] < inf);
  }

  bool dijkstra() {
    for (int i = 0; i < g.n; i++) {
      dist[i] = -1;
    }
    dist[g.src] = 0;
    priority_queue<pii, vector<pii>, greater<pii>> pq;
    pq.push(mp(0, 0));
    while (pq.size()) {
      int x = pq.top().second;
      int cost = pq.top().first;
      pq.pop();
      if (dist[x] != cost)
        continue;
      for (auto &e : g.edges[x]) {
        if (e.flow == 0)
          continue;
        if (dist[e.vertex] > cost + e.cost || dist[e.vertex] == -1) {
          dist[e.vertex] = cost + e.cost;
          pq.push(mp(dist[e.vertex], e.vertex));
        }
      }
    }
    return (dist[g.dst] != -1);
  }

  pair<int, int> dfs(int x, int flow) {
    if (x == g.dst)
      return mp(flow, 0);
    visit[x] = 1;
    pii res = {0, 0};
    for (int &i = cur[x]; i < (int)g.edges[x].size(); i++) {
      int u = g.edges[x][i].vertex;
      int c = g.edges[x][i].cost;
      if (visit[u])
        continue;
      if (dist[u] != dist[x] + c)
        continue;
      if (g.edges[x][i].flow == 0)
        continue;
      pii f = dfs(u, min(flow, g.edges[x][i].flow));
      flow -= f.first;
      res += f;
      res.second += g.edges[x][i].cost * f.first;
      g.edges[x][i].flow -= f.first;
      g.edges[u][g.edges[x][i].inv].flow += f.first;
      if (flow == 0)
        break;
    }
    visit[x] = 0;
    return res;
  }

  pii run() {
    pair<int, int> x = mp(0, 0);
    for (int i = 0; i < g.n; i++) {
      visit[i] = 0;
    }
    while (bellmanford()) {
      //			cout<<g.n<<endl;
      //			for(int i=0;i<g.n;i++)
      //			{
      //				cout<<dist[i]<<' ';
      //			}
      //			cout<<endl;
      //			Sleep(1000);
      for (int i = 0; i < g.n; i++) {
        assert(visit[i] == 0);
      }
      for (int i = 0; i < g.n; i++) {
        cur[i] = 0;
      }
      pair<int, int> f = dfs(g.src, inf);
      //			cout<<"flow="<<f<<endl;
      x += f;
    }
    return x;
  }
};
using namespace std;
int n, m;
char c[55][55];
const int dx[] = {0, 1};
const int dy[] = {1, 0};
int dist[55][55];
int id[55][55];
int rhsNum;
vector<pii> vec[105];

inline bool out(int x, int y) { return (x >= n || y >= m); }

inline int getID(int x, int y) {
  return (id[x][y] == -1 ? id[x][y] = rhsNum++ : id[x][y]);
}

inline void bfs(int sx, int sy, int id) {
  queue<tuple<int, int>> que;
  que.push(make_tuple(sx, sy));
  for (int i = 0; i < n; i++) {
    for (int j = 0; j < m; j++) {
      dist[i][j] = -inf;
    }
  }
  //	memset(dist,-1,sizeof(dist));
  dist[sx][sy] = 0;
  while (que.size()) {
    int x, y;
    tie(x, y) = que.front();
    que.pop();
    for (int i = 0; i < 2; i++) {
      int nx = x + dx[i];
      int ny = y + dy[i];
      if (out(nx, ny) || dist[nx][ny] != -inf || c[nx][ny] == '#')
        continue;
      dist[nx][ny] = dist[x][y] + 1;
      que.push(make_tuple(nx, ny));
    }
  }
  vector<tuple<int, int, int>> vSort;
  for (int i = 0; i < n; i++) {
    for (int j = 0; j < n; j++) {
      vSort.push_back(make_tuple(dist[i][j], i, j));
    }
  }
  sort(all(vSort));
  reverse(all(vSort));
  for (int i = 0; i < min(100, (int)vSort.size()); i++) {
    vec[id].push_back(
        mp(getID(get<1>(vSort[i]), get<2>(vSort[i])), get<0>(vSort[i])));
  }
}

int main() {
  //	freopen("input.txt","r",stdin);
  memset(id, -1, sizeof(id));
  cin >> n >> m;
  for (int i = 0; i < n; i++) {
    scanf("%s", c[i]);
  }
  NetworkWithCost g;
  g.init(n * m + 2);
  int src = n * m, dst = src + 1;
  g.feedsd(src, dst);
  for (int i = 0; i < n; i++) {
    for (int j = 0; j < m; j++) {
      if (c[i][j] == '#')
        continue;
      if (!out(i + 1, j) && c[i + 1][j] != '#') {
        g.addEdge(i * m + j, (i + 1) * m + j, inf, 0);
      }
      if (!out(i, j + 1) && c[i][j + 1] != '#') {
        g.addEdge(i * m + j, (i)*m + (j + 1), inf, 0);
      }
      if (c[i][j] == 'o')
        g.addEdge(src, i * m + j, 1, i + j);
      g.addEdge(i * m + j, dst, 1, -i - j);
    }
  }
  MCMF d;
  d.init(g);
  cout << -d.run().second << endl;
  return 0;
}


Error: TLE

Fixed submission:

// Original Code:
// #include <self/utility>
// #include <self/debug>
// #include <self/mcmf>
// using namespace std;
// int n,m;
// char c[55][55];
// const int dx[]={0,1};
// const int dy[]={1,0};
// int dist[55][55];
// int id[55][55];
// int rhsNum;
// vector <pii> vec[105];
//
// inline bool out(int x,int y)
//{
//	return (x>=n || y>=m);
// }
//
// inline int getID(int x,int y)
//{
//	return (id[x][y]==-1?id[x][y]=rhsNum++:id[x][y]);
// }
//
// inline void bfs(int sx,int sy,int id)
//{
//	queue <tuple<int,int> > que;
//	que.push(make_tuple(sx,sy));
//	for(int i=0;i<n;i++)
//	{
//		for(int j=0;j<m;j++)
//		{
//			dist[i][j]=-inf;
//		}
//	}
////	memset(dist,-1,sizeof(dist));
//	dist[sx][sy]=0;
//	while(que.size())
//	{
//		int x,y;
//		tie(x,y)=que.front();
//		que.pop();
//		for(int i=0;i<2;i++)
//		{
//			int nx=x+dx[i];
//			int ny=y+dy[i];
//			if(out(nx,ny) || dist[nx][ny]!=-inf || c[nx][ny]=='#')
//continue; 			dist[nx][ny]=dist[x][y]+1; 			que.push(make_tuple(nx,ny));
//		}
//	}
//	vector <tuple<int,int,int> > vSort;
//	for(int i=0;i<n;i++)
//	{
//		for(int j=0;j<n;j++)
//		{
//			vSort.push_back(make_tuple(dist[i][j],i,j));
//		}
//	}
//	sort(all(vSort));
//	reverse(all(vSort));
//	for(int i=0;i<min(100,(int)vSort.size());i++)
//	{
//		vec[id].push_back(mp(getID(get<1>(vSort[i]),get<2>(vSort[i])),get<0>(vSort[i])));
//	}
//}
//
// int main()
//{
////	freopen("input.txt","r",stdin);
//	memset(id,-1,sizeof(id));
//	cin>>n>>m;
//	for(int i=0;i<n;i++)
//	{
//		scanf("%s",c[i]);
//	}
//	NetworkWithCost g;
//	g.init(n*m+2);
//	int src=n*m,dst=src+1;
//	g.feedsd(src,dst);
//	for(int i=0;i<n;i++)
//	{
//		for(int j=0;j<m;j++)
//		{
//			if(c[i][j]=='#') continue;
//			if(!out(i+1,j) && c[i+1][j]!='#')
//			{
//				g.addEdge(i*m+j,(i+1)*m+j,inf,-1);
//			}
//			if(!out(i,j+1) && c[i][j+1]!='#')
//			{
//				g.addEdge(i*m+j,(i)*m+(j+1),inf,-1);
//			}
//			if(c[i][j]=='o') g.addEdge(src,i*m+j,1,0);
//			g.addEdge(i*m+j,dst,1,0);
//		}
//	}
////	int ids=0;
////	for(int i=0;i<n;i++)
////	{
////		for(int j=0;j<m;j++)
////		{
////			if(c[i][j]=='o')
////			{
////				bfs(i,j,ids);
////				ids++;
//////				cout<<mp(i,j)<<" is "<<ids<<endl;
//////				for(int kx=0;kx<n;kx++)
//////				{
//////					for(int ky=0;ky<m;ky++)
//////					{
//////						cout<<dist[kx][ky]<<' ';
//////					}
//////					cout<<endl;
//////				}
//////				cout<<endl;
////			}
////		}
////	}
////	int nodes=ids+rhsNum+2;
////	int src=nodes-2,dst=nodes-1;
////	NetworkWithCost g;
////	g.init(nodes);
////	g.feedsd(nodes-2,nodes-1);
////	for(int i=0;i<ids;i++)
////	{
////		for(auto [x,y]:vec[i])
////		{
////			g.addEdge(i,x+ids,1,-y);
//////			cout<<i<<"->"<<x<<":cost="<<y<<endl;
////		}
////	}
////	for(int i=0;i<ids;i++)
////	{
////		g.addEdge(src,i,1,0);
////	}
////	for(int i=0;i<rhsNum;i++)
////	{
////		g.addEdge(ids+i,dst,1,0);
////	}
//	MCMF d;
//	d.init(g);
//	cout<<-d.run().second<<endl;
//	return 0;
//}

// substituted with C++ Inliner
#ifndef _SELF_UTILITY
#define _SELF_UTILITY 1
#include <algorithm>
#include <assert.h>
#include <bitset>
#include <cmath>
#include <iostream>
#include <map>
#include <numeric>
#include <queue>
#include <set>
#include <stack>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <string>
#include <time.h>
#include <vector>
#define Endl endl
#define mp make_pair
#define ll long long
#define ull unsigned long long
#define pii pair<int, int>
#define over(A)                                                                \\
  {                                                                            \\
    cout << A << endl;                                                         \\
    exit(0);                                                                   \\
  }
#define all(A) A.begin(), A.end()
#define quickcin ios_base::sync_with_stdio(false);
const int mod = 998244353;
const int gmod = 2;
const int inf = 1039074182;
const ll llinf = 1LL * inf * inf;
template <typename T1, typename T2> inline void chmin(T1 &x, T2 b) {
  if (b < x)
    x = b;
}
template <typename T1, typename T2> inline void chmax(T1 &x, T2 b) {
  if (b > x)
    x = b;
}
template <typename T1, typename T2> inline void chadd(T1 &x, T2 b) {
  x += b;
  if (x >= mod)
    x -= mod;
}
template <typename T1, typename T2> inline void chmul(T1 &x, T2 b) {
  x = 1LL * x * b % mod;
}
template <typename T1, typename T2> inline void chmod(T1 &x, T2 b) {
  x %= b, x += b;
  if (x >= b)
    x -= b;
}
#endif

#ifndef _SELF_DEBUG
#define _SELF_DEBUG 1
#ifndef _SELF_OPERATOR
#define _SELF_OPERATOR 1
using namespace std;
template <typename T> ostream &operator<<(ostream &cout, vector<T> vec) {
  cout << "{";
  for (int i = 0; i < (int)vec.size(); i++) {
    cout << vec[i];
    if (i != (int)vec.size() - 1)
      cout << ',';
  }
  cout << "}";
  return cout;
}

template <typename T1, typename T2>
ostream &operator<<(ostream &cout, pair<T1, T2> p) {
  cout << "(" << p.first << ',' << p.second << ")";
  return cout;
}

template <typename T, typename T2>
ostream &operator<<(ostream &cout, set<T, T2> s) {
  vector<T> t;
  for (auto x : s)
    t.push_back(x);
  cout << t;
  return cout;
}

template <typename T> ostream &operator<<(ostream &cout, multiset<T> s) {
  vector<T> t;
  for (auto x : s)
    t.push_back(x);
  cout << t;
  return cout;
}

template <typename T> ostream &operator<<(ostream &cout, queue<T> q) {
  vector<T> t;
  while (q.size()) {
    t.push_back(q.front());
    q.pop();
  }
  cout << t;
  return cout;
}

template <typename T1, typename T2>
ostream &operator<<(ostream &cout, map<T1, T2> m) {
  for (auto &x : m) {
    cout << "Key: " << x.first << ' ' << "Value: " << x.second << endl;
  }
  return cout;
}

template <typename T> T operator*(vector<T> v1, vector<T> v2) {
  assert(v1.size() == v2.size());
  int n = v1.size();
  T res = 0;
  for (int i = 0; i < n; i++) {
    res += v1[i] * v2[i];
  }
  return res;
}

template <typename T1, typename T2>
pair<T1, T2> operator+(pair<T1, T2> x, pair<T1, T2> y) {
  return make_pair(x.first + y.first, x.second + y.second);
}

template <typename T1, typename T2>
void operator+=(pair<T1, T2> &x, pair<T1, T2> y) {
  x.first += y.first;
  x.second += y.second;
}

template <typename T1, typename T2> pair<T1, T2> operator-(pair<T1, T2> x) {
  return make_pair(-x.first, -x.second);
}

template <typename T> vector<vector<T>> operator~(vector<vector<T>> vec) {
  vector<vector<T>> v;
  int n = vec.size(), m = vec[0].size();
  v.resize(m);
  for (int i = 0; i < m; i++) {
    v[i].resize(n);
  }
  for (int i = 0; i < m; i++) {
    for (int j = 0; j < n; j++) {
      v[i][j] = vec[j][i];
    }
  }
  return v;
}
#endif

void print0x(int x) {
  std::vector<int> vec;
  while (x) {
    vec.push_back(x & 1);
    x >>= 1;
  }
  std::reverse(vec.begin(), vec.end());
  for (int i = 0; i < (int)vec.size(); i++) {
    std::cout << vec[i];
  }
  std::cout << ' ';
}

template <typename T> void print0x(T x, int len) {
  std::vector<int> vec;
  while (x) {
    vec.push_back(x & 1);
    x >>= 1;
  }
  reverse(vec.begin(), vec.end());
  for (int i = vec.size(); i < len; i++) {
    putchar('0');
  }
  for (int i = 0; i < vec.size(); i++) {
    std::cout << vec[i];
  }
  std::cout << ' ';
}
#endif

struct NetworkWithCost {
  struct Edge {
    int vertex;
    int flow;
    int cost;
    int inv;
  };
  vector<Edge> *edges;
  inline void addEdge(int x, int y, int limit, int cost) {
    Edge edge;
    edge.cost = cost;
    edge.flow = limit;
    edge.vertex = y;
    edge.inv = (int)edges[y].size();
    edges[x].push_back(edge);
    edge.vertex = x;
    edge.flow = 0;
    edge.cost = -cost;
    edge.inv = (int)edges[x].size() - 1;
    edges[y].push_back(edge);
  }
  int src, dst;
  int n;
  void init(int _n) {
    n = _n;
    edges = new vector<Edge>[n];
    src = dst = -1;
  }
  void feedsd(int _src, int _dst) {
    src = _src;
    dst = _dst;
  }
  void clear() {
    for (int i = 0; i < n; i++) {
      edges[i].clear();
    }
    src = dst = -1;
  }
};

namespace MCMFSpace {
void operator+=(pii &a, const pii &b) {
  a.first += b.first;
  a.second += b.second;
}
} // namespace MCMFSpace

struct MCMF {
  const int DistInf = 1039074182;
  NetworkWithCost g;
  int *dist;
  bool *visit;
  int *cur;
  queue<int> que;
  inline void init(NetworkWithCost &_g) {
    g = _g;
    dist = new int[g.n + 5];
    visit = new bool[g.n + 5];
    cur = new int[g.n + 5];
  }

  bool bellmanford() {
    //	cout<<"Bf started";
    for (int i = 0; i < g.n; i++) {
      dist[i] = inf;
    }
    dist[g.src] = 0;
    for (int T = 0; T < g.n; T++) {
      for (int i = 0; i < g.n; i++) {
        if (dist[i] == inf)
          continue;
        for (auto &e : g.edges[i]) {
          if (e.flow == 0)
            continue;
          if (dist[e.vertex] > dist[i] + e.cost) {
            dist[e.vertex] = dist[i] + e.cost;
          }
        }
      }
    }
    //	system("pause");
    return (dist[g.dst] < inf);
  }

  bool dijkstra() {
    for (int i = 0; i < g.n; i++) {
      dist[i] = -1;
    }
    dist[g.src] = 0;
    priority_queue<pii, vector<pii>, greater<pii>> pq;
    pq.push(mp(0, 0));
    while (pq.size()) {
      int x = pq.top().second;
      int cost = pq.top().first;
      pq.pop();
      if (dist[x] != cost)
        continue;
      for (auto &e : g.edges[x]) {
        if (e.flow == 0)
          continue;
        if (dist[e.vertex] > cost + e.cost || dist[e.vertex] == -1) {
          dist[e.vertex] = cost + e.cost;
          pq.push(mp(dist[e.vertex], e.vertex));
        }
      }
    }
    return (dist[g.dst] != -1);
  }

  pair<int, int> dfs(int x, int flow) {
    if (x == g.dst)
      return mp(flow, 0);
    visit[x] = 1;
    pii res = {0, 0};
    for (int &i = cur[x]; i < (int)g.edges[x].size(); i++) {
      int u = g.edges[x][i].vertex;
      int c = g.edges[x][i].cost;
      if (visit[u])
        continue;
      if (dist[u] != dist[x] + c)
        continue;
      if (g.edges[x][i].flow == 0)
        continue;
      pii f = dfs(u, min(flow, g.edges[x][i].flow));
      flow -= f.first;
      res += f;
      res.second += g.edges[x][i].cost * f.first;
      g.edges[x][i].flow -= f.first;
      g.edges[u][g.edges[x][i].inv].flow += f.first;
      if (flow == 0)
        break;
    }
    visit[x] = 0;
    return res;
  }

  pii run() {
    pair<int, int> x = mp(0, 0);
    for (int i = 0; i < g.n; i++) {
      visit[i] = 0;
    }
    while (bellmanford()) {
      //			cout<<g.n<<endl;
      //			for(int i=0;i<g.n;i++)
      //			{
      //				cout<<dist[i]<<' ';
      //			}
      //			cout<<endl;
      //			Sleep(1000);
      for (int i = 0; i < g.n; i++) {
        assert(visit[i] == 0);
      }
      for (int i = 0; i < g.n; i++) {
        cur[i] = 0;
      }
      pair<int, int> f = dfs(g.src, inf);
      //			cout<<"flow="<<f<<endl;
      x += f;
    }
    return x;
  }
};
using namespace std;
int n, m;
char c[55][55];
const int dx[] = {0, 1};
const int dy[] = {1, 0};
int dist[55][55];
int id[55][55];
int rhsNum;
vector<pii> vec[105];

inline bool out(int x, int y) { return (x >= n || y >= m); }

inline int getID(int x, int y) {
  return (id[x][y] == -1 ? id[x][y] = rhsNum++ : id[x][y]);
}

inline void bfs(int sx, int sy, int id) {
  queue<tuple<int, int>> que;
  que.push(make_tuple(sx, sy));
  for (int i = 0; i < n; i++) {
    for (int j = 0; j < m; j++) {
      dist[i][j] = -inf;
    }
  }
  //	memset(dist,-1,sizeof(dist));
  dist[sx][sy] = 0;
  while (que.size()) {
    int x, y;
    tie(x, y) = que.front();
    que.pop();
    for (int i = 0; i < 2; i++) {
      int nx = x + dx[i];
      int ny = y + dy[i];
      if (out(nx, ny) || dist[nx][ny] != -inf || c[nx][ny] == '#')
        continue;
      dist[nx][ny] = dist[x][y] + 1;
      que.push(make_tuple(nx, ny));
    }
  }
  vector<tuple<int, int, int>> vSort;
  for (int i = 0; i < n; i++) {
    for (int j = 0; j < n; j++) {
      vSort.push_back(make_tuple(dist[i][j], i, j));
    }
  }
  sort(all(vSort));
  reverse(all(vSort));
  for (int i = 0; i < min(100, (int)vSort.size()); i++) {
    vec[id].push_back(
        mp(getID(get<1>(vSort[i]), get<2>(vSort[i])), get<0>(vSort[i])));
  }
}

int main() {
  //	freopen("input.txt","r",stdin);
  memset(id, -1, sizeof(id));
  cin >> n >> m;
  for (int i = 0; i < n; i++) {
    scanf("%s", c[i]);
  }
  NetworkWithCost g;
  g.init(n * m + 2);
  int src = n * m, dst = src + 1;
  g.feedsd(src, dst);
  for (int i = 0; i < n; i++) {
    for (int j = 0; j < m; j++) {
      if (c[i][j] == '#')
        continue;
      if (!out(i + 1, j) && c[i + 1][j] != '#') {
        g.addEdge(i * m + j, (i + 1) * m + j, inf, -1);
      }
      if (!out(i, j + 1) && c[i][j + 1] != '#') {
        g.addEdge(i * m + j, (i)*m + (j + 1), inf, -1);
      }
      if (c[i][j] == 'o')
        g.addEdge(src, i * m + j, 1, 0);
      g.addEdge(i * m + j, dst, 1, 0);
    }
  }
  //	int ids=0;
  //	for(int i=0;i<n;i++)
  //	{
  //		for(int j=0;j<m;j++)
  //		{
  //			if(c[i][j]=='o')
  //			{
  //				bfs(i,j,ids);
  //				ids++;
  ////				cout<<mp(i,j)<<" is "<<ids<<endl;
  ////				for(int kx=0;kx<n;kx++)
  ////				{
  ////					for(int ky=0;ky<m;ky++)
  ////					{
  ////						cout<<dist[kx][ky]<<' ';
  ////					}
  ////					cout<<endl;
  ////				}
  ////				cout<<endl;
  //			}
  //		}
  //	}
  //	int nodes=ids+rhsNum+2;
  //	int src=nodes-2,dst=nodes-1;
  //	NetworkWithCost g;
  //	g.init(nodes);
  //	g.feedsd(nodes-2,nodes-1);
  //	for(int i=0;i<ids;i++)
  //	{
  //		for(auto [x,y]:vec[i])
  //		{
  //			g.addEdge(i,x+ids,1,-y);
  ////			cout<<i<<"->"<<x<<":cost="<<y<<endl;
  //		}
  //	}
  //	for(int i=0;i<ids;i++)
  //	{
  //		g.addEdge(src,i,1,0);
  //	}
  //	for(int i=0;i<rhsNum;i++)
  //	{
  //		g.addEdge(ids+i,dst,1,0);
  //	}
  MCMF d;
  d.init(g);
  cout << -d.run().second << endl;
  return 0;
}