#include<iostream>
#include<algorithm>
#include<cstdio>
#include<cmath>
#include<cstring>
#include<map>
#include<stack>
#include<queue>
#include<ctime>
#include<vector>
#include<set>
#include<cstdlib>
#include<utility>
using namespace std;
int fa[1000+5],ans;
char a[1000+5][1000+5];
string s;
int get(int x)
{
    if (fa[x]==x)
        return x;
    return fa[x]=get(fa[x]);
}
void merge(int x,int y)
{
    if (get(x)==get(y))
        return;
    ans--;
    fa[get(y)]=get(x);
}
int main()
{
    int n,m,i,j,minn;
    scanf("%d%d",&n,&m);
    ans=n-1;
    for (i=1;i<=n;i++)
    {
        cin >> s;
        for (j=1;j<=m;j++)
            a[i][j]=s[j-1];
    }
    a[1][1]=a[1][m]=a[n][1]=a[n][m]='#';
    for (i=1;i<=n;i++)
        fa[i]=i;
    for (j=1;j<=m;j++)
    {
        int last=0;
        for (i=1;i<=n;i++)
            if (a[i][j]=='#')
            {
                if (last!=0)
                    merge(last,i);
                last=i;
            }
    }
    minn=ans;
    ans=m-1;
    for (i=1;i<=m;i++)
        fa[i]=i;
    for (i=1;i<=n;i++)
    {
        int last=0;
        for (j=1;j<=m;j++)
            if (a[i][j]=='#')
            {
                if (last!=0)
                    merge(last,j);
                last=j;
            }
    }
    minn=min(minn,ans);
    printf("%d\n",minn);
}

#include <bits/stdc++.h>
#define rep(a,b,c) for(int a = b; a < c; a++)
#define rep2(a,b,c) for(ll a = c - 1; a >=b; a--)
#define all(x) (x).begin(), (x).end()
#define pb push_back
#define x first
#define y second
using namespace std;
using ll = long long;
using tl = tuple<ll, ll, ll, ll>;
using pl = pair<ll, ll>;
using pi = pair<int, int>;
using ld = long double;


struct dsu {
	// if u is root : par[u] = -(size of tree)
	// else: par[u] = parent of u
public:
	dsu() : n(0) {}
	explicit dsu(int n):n(n), par(n, -1){}
	int merge(int u, int v){
		assert(0 <= u && u < n);
		assert(0 <= v && v < n);
		u = find(u); v = find(v);
		if (u == v) return u;
		if (-par[u] < -par[v]) swap(u, v);
		par[u] += par[v];
		par[v] = u;
		return u;
	}
	int find(int u) {
		assert(0 <= u && u < n);
		if (par[u] < 0) return u;
		return par[u] = find(par[u]);
	}
	bool same(int u, int v) {
		assert(0 <= u && u < n);
		assert(0 <= v && v < n);
		return find(u) == find(v);
	}
	int size(int u) {
		assert(0 <= u && u < n);
		return -par[find(u)];
	}
	vector<vector<int> > groups() {
		vector<int> roots(n), groups(n);
		for (int i = 0; i < n; i++) {
			roots[i] = find(i);
			groups[roots[i]]++;
		}
		vector<vector<int> > result(n);
		for (int i = 0; i < n; i++) {
			result[i].reserve(groups[i]);
		}
		for (int i = 0; i < n; i++) {
			result[roots[i]].push_back(i);
		}
		result.erase(
			remove_if(result.begin(), result.end(), [&](const vector<int>& v) { return v.empty(); })
		);
		return result;
	}
private:
	int n;
	vector<int> par;
};

int H, W;
string S[1001];
dsu DSU;
int main() {
	cin.tie(0); cout.tie(0); ios_base::sync_with_stdio(false);
	cin >> H >> W;
	rep(i, 0, H) cin >> S[i];
	DSU = dsu(H + W);
	DSU.merge(0, H + 0);
	DSU.merge(0, H + W - 1);
	DSU.merge(H - 1, H + 0);
	DSU.merge(H - 1, H + W - 1);
	rep(i, 0, H)rep(j, 0, W) {
		if (S[i][j] == '#') DSU.merge(i, H + j);
	}
	map<int, int> m1, m2;
	rep(i, 0, H) m1[DSU.find(i)]++;
	rep(i, 0, W) m2[DSU.find(H + i)]++;
	cout << min(m1.size() - 1, m2.size() - 1);
}
