//Let's join Kaede Takagaki Fan Club !!
#pragma GCC optimize("Ofast")
#pragma GCC optimize("unroll-loops")
#include <bits/stdc++.h>
#include <ext/pb_ds/assoc_container.hpp>
#include <ext/pb_ds/tree_policy.hpp>
using namespace std;
//#define int long long
typedef long long ll;
typedef pair<int,int> P;
typedef pair<int,P> P1;
typedef pair<P,P> P2;
#define pu push
#define pb push_back
#define eb emplace_back
#define mp make_pair
#define eps 1e-7
#define INF 1000000000
#define a first
#define b second
#define fi first
#define sc second
#define rng(i,a,b) for(int i=int(a);i<int(b);i++)
#define rep(i,x) for(int i=0;i<x;i++)
#define repn(i,x) for(int i=1;i<=x;i++)
#define SORT(x) sort(x.begin(),x.end())
#define ERASE(x) x.erase(unique(x.begin(),x.end()),x.end())
#define POSL(x,v) (lower_bound(x.begin(),x.end(),v)-x.begin())
#define POSU(x,v) (upper_bound(x.begin(),x.end(),v)-x.begin())
#define all(x) x.begin(),x.end()
#define si(x) int(x.size())

#ifdef LOCAL
#define dmp(x) cerr<<__LINE__<<" "<<#x<<" "<<x<<endl
#else
#define dmp(x) void(0)
#endif

template<class t,class u> bool chmax(t&a,u b){if(a<b){a=b;return true;}else return false;}
template<class t,class u> bool chmin(t&a,u b){if(b<a){a=b;return true;}else return false;}

template<class t> using vc=vector<t>;

template<class t,class u>
ostream& operator<<(ostream& os,const pair<t,u>& p){
	return os<<"{"<<p.fi<<","<<p.sc<<"}";
}

template<class t> ostream& operator<<(ostream& os,const vc<t>& v){
	os<<"{";
	for(auto e:v)os<<e<<",";
	return os<<"}";
}

template<class T>
void g(T &a){
	cin >> a;
}
template<class T>
void o(const T &a,bool space=false){
	cout << a << (space?' ':'\n');
}
//ios::sync_with_stdio(false);
const ll mod = 998244353;
mt19937_64 mt(chrono::steady_clock::now().time_since_epoch().count());
template<class T>
void add(T&a,T b){
	a+=b;
	if(a >= mod) a-=mod;
}
ll modpow(ll x,ll n){
	ll res=1;
	while(n>0){
		if(n&1) res=res*x%mod;
		x=x*x%mod;
		n>>=1;
	}
	return res;
}
int par[2205],ran[2205];
void init(){ for(int i=0;i<2205;i++) par[i] = i; }
int find(int x){ if(x == par[x]) return x; else return par[x] = find(par[x]); }
void unite(int x,int y){
	x = find(x); y = find(y); if(x==y) return;
	if(ran[x] < ran[y]) par[x] = y;
	else{
		par[y] = x;
		if(ran[x] == ran[y]) ran[x]++;
	}
}
bool same(int x,int y){ return find(x)==find(y); }
int n, m;
string str[1005];

void solve(){
	init();
	cin >> n >> m;
	rep(i, n) cin >> str[i];
	unite(0, n); unite(0, n+m-1);
	unite(n-1, n); unite(n-1, n+m-1);
	rep(i, n){
		rep(j, m){
			if(str[i][j] == '#'){
				unite(i, j + n);
			}
		}
	}
	set<int>x, y;
	rep(i, n) x.insert(find(i));
	rep(i, m) y.insert(find(n + i));
	
	cout << min(si(x), si(y)) - 1 << endl;
}
signed main(){
	cin.tie(0);
	ios::sync_with_stdio(0);
	cout<<fixed<<setprecision(20);
	int t; t = 1; //cin >> t;
	while(t--) solve();
}

#include <stdio.h>
#include <set>
#define MN 1000

int h,w,fa[MN*2+5];
char s[MN+5][MN+5];

int r(int x){
	return x;
}

int c(int x){
	return x+h;
}

int gf(int u){
	return fa[u]==u?u:fa[u]=gf(fa[u]);
}

void unite(int u,int v){
	u = gf(u);
	v = gf(v);
	if(u==v) return;
	fa[v] = u;
}

int main(){
	scanf("%d%d",&h,&w);
	for(int i=1;i<=h+w;i++)
		fa[i] = i;
	for(int i=1;i<=h;i++)
		scanf("%s",&s[i][1]);
	unite(r(1),r(h));
	unite(c(1),c(w));
	unite(r(1),c(1));
	for(int i=1;i<=h;i++)
		for(int j=1;j<=w;j++)
			if(s[i][j]=='#')
				unite(r(i),c(j));
	int ans = 0x3fffffff;
	{
		std::set<int> s;
		for(int i=1;i<=h;i++)
			s.insert(gf(r(i)));
		ans = std::min(ans,(int)s.size()-1);
	}
	{
		std::set<int> s;
		for(int i=1;i<=w;i++)
			s.insert(gf(c(i)));
		ans = std::min(ans,(int)s.size()-1);
	}
	printf("%d\n",ans);
}