#include <bits/stdc++.h>
#pragma GCC optimize(2)
using namespace std;
const int maxn = 3e6;
const int INF = 0x7fffffff;
const int mod = 1e9 + 7;
const double eps = 1e-7;
const double Pi = acos(-1.0);
inline int read_int() {
  char c;
  int ret = 0, sgn = 1;
  do {
    c = getchar();
  } while ((c < '0' || c > '9') && c != '-');
  if (c == '-')
    sgn = -1;
  else
    ret = c - '0';
  while ((c = getchar()) >= '0' && c <= '9') ret = ret * 10 + (c - '0');
  return sgn * ret;
}
inline long long read_ll() {
  char c;
  long long ret = 0, sgn = 1;
  do {
    c = getchar();
  } while ((c < '0' || c > '9') && c != '-');
  if (c == '-')
    sgn = -1;
  else
    ret = c - '0';
  while ((c = getchar()) >= '0' && c <= '9') ret = ret * 10 + (c - '0');
  return sgn * ret;
}
inline long long quick_pow(long long base, long long index, long long p) {
  long long res = 1;
  while (index) {
    if (index & 1) res = res * base % p;
    base = base * base % p;
    index >>= 1;
  }
  return res;
}
struct edge {
  edge(int _to, int _cap, int _rev) : to(_to), capacity(_cap), reverse(_rev) {}
  edge() {}
  int to, capacity, reverse;
};
class Dinic {
 public:
  void Init(int n) {
    for (int i = 0; i <= n; ++i) G[i].clear();
  }
  inline void Add_edge(int from, int to, int cap) {
    G[from].push_back(edge(to, cap, G[to].size()));
    G[to].push_back(edge(from, 0, G[from].size() - 1));
  }
  void BFS(int s) {
    memset(Deep, -1, sizeof(Deep));
    queue<int> q;
    Deep[s] = 0;
    q.push(s);
    while (!q.empty()) {
      int v = q.front();
      q.pop();
      for (int i = 0; i < G[v].size(); ++i) {
        edge &e = G[v][i];
        if (e.capacity > 0 && Deep[e.to] < 0) {
          Deep[e.to] = Deep[v] + 1;
          q.push(e.to);
        }
      }
    }
  }
  int DFS(int v, int t, int f) {
    if (v == t) return f;
    for (int &i = iter[v]; i < G[v].size(); ++i) {
      edge &e = G[v][i];
      if (e.capacity > 0 && Deep[v] < Deep[e.to]) {
        int d = DFS(e.to, t, min(f, e.capacity));
        if (d > 0) {
          e.capacity -= d;
          G[e.to][e.reverse].capacity += d;
          return d;
        }
      }
    }
    return 0;
  }
  int dinic(int s, int t) {
    int maxflow = 0;
    while (true) {
      BFS(s);
      if (Deep[t] < 0) return maxflow;
      memset(iter, 0, sizeof(iter));
      int f;
      while ((f = DFS(s, t, INF)) > 0) maxflow += f;
    }
  }

 private:
  vector<edge> G[maxn + 5];
  int Deep[maxn + 5], iter[maxn + 5];
};
Dinic Dic;
int n, m, S, t;
int id(int x, int y) { return (x - 1) * m + y; }
bool check(int x, int y) { return x > 0 && x <= n && y > 0 && y <= m; }
char s[maxn + 5];
set<pair<int, int> > st;
int main() {
  n = read_int(), m = read_int();
  S = id(1, 1), t = id(n, m);
  Dic.Init(t);
  for (int i = 1; i <= n; ++i) {
    scanf("%s", s + 1);
    for (int j = 1; j <= m; ++j) {
      if (s[j] == '#') st.insert(pair<int, int>(i, j));
      if (i == 1 && j == 1) continue;
      if (i == n && j == m) continue;
      Dic.Add_edge(id(i, j), id(i, j) + n * m, 1);
    }
  }
  for (int i = 1; i <= n; ++i) {
    for (int j = 1; j <= m; ++j) {
      if (st.count(pair<int, int>(i, j))) continue;
      int x = i, y = j + 1;
      if (check(x, y) && !st.count(pair<int, int>(x, y))) {
        if (i == 1 && j == 1) Dic.Add_edge(id(i, j), id(x, y), 1);
        Dic.Add_edge(id(i, j) + n * m, id(x, y), 1);
      }
      x = i + 1, y = j;
      if (check(x, y) && !st.count(pair<int, int>(x, y))) {
        if (i == 1 && j == 1) Dic.Add_edge(id(i, j), id(x, y), 1);
        Dic.Add_edge(id(i, j) + n * m, id(x, y), 1);
      }
    }
  }
  int res = Dic.dinic(S, t);
  cout << res << endl;
  return 0;
}
