#include<bits/stdc++.h>
using namespace std;
#define ALL(x) begin(x),end(x)
#define rep(i,n) for(int i=0;i<(n);i++)
#define debug(v) cout<<#v<<":";for(auto x:v){cout<<x<<' ';}cout<<endl;
#define mod 1000000007
using ll=long long;
const int INF=1000000000;
const ll LINF=1001002003004005006ll;
int dx[]={1,0,-1,0},dy[]={0,1,0,-1};
// ll gcd(ll a,ll b){return b?gcd(b,a%b):a;}
template<class T>bool chmax(T &a,const T &b){if(a<b){a=b;return true;}return false;}
template<class T>bool chmin(T &a,const T &b){if(b<a){a=b;return true;}return false;}

struct IOSetup{
    IOSetup(){
        cin.tie(0);
        ios::sync_with_stdio(0);
        cout<<fixed<<setprecision(12);
    }
} iosetup;
 
template<typename T>
ostream &operator<<(ostream &os,const vector<T>&v){
    for(int i=0;i<(int)v.size();i++) os<<v[i]<<(i+1==(int)v.size()?"":" ");
    return os;
}
template<typename T>
istream &operator>>(istream &is,vector<T>&v){
    for(T &x:v)is>>x;
    return is;
}

struct UnionFind{
    private:
    vector<int> par,siz;

    public:
    int con;
    UnionFind(int n):par(n),siz(n,1),con(n){
        iota(begin(par),end(par),0);
    }
    int root(int x){
        return (par[x]==x?x:(par[x]=root(par[x])));
    }
    bool sameroot(int x,int y){
        return root(x)==root(y);
    }
    bool unite(int x,int y){
        x=root(x);y=root(y);
        if(x==y) return false;
        if(siz[x]<siz[y])swap(x,y);
        siz[x]+=siz[y];
        par[y]=x;
        con--;
        return true;
    }
    int size(int x){
        return siz[root(x)];
    }
};

signed main(){
    int h,w;cin>>h>>w;
    UnionFind uf(h+w);
    rep(i,h){
        rep(j,w){
            char c;cin>>c;
            if(c=='#'){
                uf.unite(i,h+j);
            }
        }
    }

    uf.unite(0,h);
    uf.unite(0,h+w-1);
    uf.unite(h-1,h);
    uf.unite(h-1,h+w-1);


    int res=INF;
    // left
    {
        UnionFind l(h);

        vector<vector<int>> v(h+w);
        rep(i,h) v[uf.root(i)].push_back(i);
        rep(i,h+w){
            if(v.empty()) continue;
            for(int j=1;j<(int)v[i].size();j++) l.unite(v[i][0],v[i][j]);
        }
        chmin(res,l.con-1);
    }
    {
        UnionFind r(w);

        vector<vector<int>> v(h+w);
        rep(i,w) v[uf.root(h+i)].push_back(i);
        rep(i,h+w){
            if(v.empty()) continue;
            for(int j=1;j<(int)v[i].size();j++) r.unite(v[i][0],v[i][j]);
        }
        chmin(res,r.con-1);
    }
    cout<<res<<endl;
    return 0;
}


/*

4 5
.....
.###.
.....
.....

*/
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <vector>
#include <iostream>
#include <cassert>
#include <cmath>
#include <string>
#include <queue>
#include <set>
#include <map>
#include <cstdlib>

using namespace std;

#define mp make_pair
#define pb push_back
#define fi first
#define se second
#define li long long
#define pii pair<int, int>
#define vi vector<int>
#define li long long

#define forn(i, n) for (int i = 0; i < (int)n; i++)
#define fore(i, b, e) for (int i = (int)b; i <= (int)e; i++)

const int MAXN = 2005;

bool visited[MAXN];
vi edges[MAXN];
int n, m;

void dfs(int v) {
	visited[v] = true;
	for (int u : edges[v]) {
		if (!visited[u])
			dfs(u);
	}
}

void add_edge(int row, int col) {
	edges[row].pb(col + n);
	edges[col + n].pb(row);
}

int main() {
	scanf("%d%d", &n, &m);
	forn(i, n) {
		string s;
		cin >> s;
		forn(j, m) {
			if (s[j] == '#') {
				add_edge(i, j);
			}
		}
	}
	/*forn(i, n) {
		add_edge(i, 0);
		add_edge(i, m - 1);
	}
	forn(j, m) {
		add_edge(0, j);
		add_edge(n - 1, j);
	}*/
	add_edge(0, 0);
	add_edge(0, m);
	add_edge(n - 1, 0);
	add_edge(n - 1, m - 1);
	int row_comp = 0;
	forn(i, n) {
		if (!visited[i]) {
			++row_comp;
			dfs(i);
		}
	}
	memset(visited, false, sizeof(visited));
	int col_comp = 0;
	fore(i, n, n + m - 1) {
		if (!visited[i]) {
			++col_comp;
			dfs(i);
		}
	}
	//cerr << row_comp << " " << col_comp << endl;
	printf("%d", min(row_comp - 1, col_comp - 1));
}