#include <bits/stdc++.h>
using namespace std;
#define rep(i, n) for(int i = 0; i < n; i++)
#define rep2(i, x, n) for(int i = x; i <= n; i++)
#define rep3(i, x, n) for(int i = x; i >= n; i--)
#define each(e, v) for(auto &e: v)
#define pb push_back
#define eb emplace_back
#define all(x) x.begin(), x.end()
#define rall(x) x.rbegin(), x.rend()
#define sz(x) (int)x.size()
using ll = long long;
using pii = pair<int, int>;
using pil = pair<int, ll>;
using pli = pair<ll, int>;
using pll = pair<ll, ll>;
const int MOD = 1000000007;
//const int MOD = 998244353;
const int inf = (1<<30)-1;
const ll INF = (1LL<<60)-1;
template<typename T> bool chmax(T &x, const T &y) {return (x < y)? (x = y, true) : false;};
template<typename T> bool chmin(T &x, const T &y) {return (x > y)? (x = y, true) : false;};

struct io_setup{
    io_setup(){
        ios_base::sync_with_stdio(false);
        cin.tie(NULL);
        cout << fixed << setprecision(15);
    }
} io_setup;

struct Union_Find_Tree{
    vector<int> data;
    const int n;
    
    Union_Find_Tree(int n) : n(n){
        data.assign(n, -1);
    }
    
    int root(int x){
        if(data[x] < 0) return x;
        return data[x] = root(data[x]);
    }

    int operator [] (int i) {return root(i);}
    
    bool unite(int x, int y){
        x = root(x), y = root(y);
        if(x == y) return false;
        if(data[x] > data[y]) swap(x, y);
        data[x] += data[y], data[y] = x;
        return true;
    }
    
    int size(int x) {return -data[root(x)];}
    
    bool same(int x, int y) {return root(x) == root(y);}
    
    void clear() {fill(begin(data), end(data), -1);}
};

int main(){
    int H, W; cin >> H >> W;

    vector<string> S(H);
    rep(i, H) cin >> S[i];

    vector<vector<int>> xs(H), ys(W);
    rep(i, H){
        xs[i].eb(0);
        rep2(j, 1, W-2){
            if(S[i][j] == '#') xs[i].eb(j);
        }
        xs[i].eb(W-1);
    }

    rep(j, W){
        ys[j].eb(0);
        rep2(i, 1, H-2){
            if(S[i][j] == '#') ys[j].eb(i);
        }
        ys[j].eb(H-1);
    }

    vector<vector<bool>> used(H, vector<bool>(W, false));
    vector<bool> ux(H, false), uy(W, false);
    queue<pii> que;

    used[0][0] = true;

    que.emplace(0, 0);
    while(!que.empty()){
        auto [x, y] = que.front(); que.pop();
        ux[x] = true, uy[y] = true;

        if(y > 0){
            auto it = lower_bound(all(xs[x]), y);
            --it;
            int ny = *it;
            if(!used[x][ny]){
                used[x][ny] = true; 
                que.emplace(x, ny);
            }
        }
        if(y < W-1){
            auto it = upper_bound(all(xs[x]), y);
            int ny = *it;
            if(!used[x][ny]){
                used[x][ny] = true; 
                que.emplace(x, ny);
            }
        }

        if(x > 0){
            auto it = lower_bound(all(ys[y]), x);
            --it;
            int nx = *it;
            if(!used[nx][y]){
                used[nx][y] = true; 
                que.emplace(nx, y);
            }
        }
        if(x < H-1){
            auto it = upper_bound(all(ys[y]), x);
            int nx = *it;
            if(!used[nx][y]){
                used[nx][y] = true; 
                que.emplace(nx, y);
            }
        }
    }

    vector<int> X, Y;
    rep(i, H) if(!ux[i]) X.eb(i);
    rep(i, W) if(!uy[i]) Y.eb(i);

    int A = sz(X), B = sz(Y);

    if(A == 0 || B == 0) {cout << "0\n"; return 0;}

    Union_Find_Tree uf(A+B);
    rep(i, A){
        rep(j, B){
            if(S[X[i]][Y[j]] == '#') uf.unite(i, A+j);
        }
    }

    int a = 0, b = 0;
    rep(i, A){
        bool flag = true;
        rep(j, i){
            if(uf.same(i, j)) flag = false;
        }
        a += flag;
    }
    rep(i, B){
        bool flag = true;
        rep(j, i){
            if(uf.same(A+i, A+j)) flag = false;
        }
        b += flag;
    }

    cout << min(a, b) << '\n';
}
#include <stdio.h>
#include <vector>

std::pair<int,int> next[1010][1010];
std::pair<int,int> find(std::pair<int,int> P)
{
	if(next[P.first][P.second]==P) return P;
	else return next[P.first][P.second] = find(next[P.first][P.second]);
}

char x[1010][1010];
int check[1010][1010];
int main()
{
	int a,b;
	scanf("%d%d",&a,&b);
	for(int i=1;i<=a;i++) scanf("%s",x[i]+1);
	x[1][1] = '#';
	x[1][b] = '#';
	x[a][1] = '#';
	x[a][b] = '#';
	for(int i=1;i<=a;i++) for(int j=1;j<=b;j++) next[i][j] = std::make_pair(i,j);
	
	int count1 = 0, count2 = 0;
	for(int i=1;i<=a;i++)
	{
		int last = -1;
		for(int j=1;j<=b;j++)
		{
			if(x[i][j]=='#')
			{
				if(last!=-1)
				{
					std::pair<int,int> s = std::make_pair(i,last);
					std::pair<int,int> t = std::make_pair(i,j);
					s = find(s);
					t = find(t);
					if(s.first != t.first || s.second != t.second) next[s.first][s.second] = t;
				}
				last = j;
			}
		}
		if(last==-1) count1++;
	}
	
	for(int j=1;j<=b;j++)
	{
		int last = -1;
		for(int i=1;i<=a;i++)
		{
			if(x[i][j]=='#')
			{
				if(last!=-1)
				{
					std::pair<int,int> s = std::make_pair(last,j);
					std::pair<int,int> t = std::make_pair(i,j);
					s = find(s);
					t = find(t);
					if(s.first != t.first || s.second != t.second) next[s.first][s.second] = t;
				}
				last = i;
			}
		}
		if(last==-1) count2++;
	}
	
	int ans = 0;
	for(int i=1;i<=a;i++)
	{
		for(int j=1;j<=b;j++)
		{
			if(x[i][j]=='#')
			{
				std::pair<int,int> s = std::make_pair(i,j);
				s = find(s);
				if(s==std::make_pair(i,j) && check[i][j]==0)
				{
					//printf("%d %d??\n",i,j);
					ans++;
					check[i][j] = 1;
				}
			}
		}
	}
	int ans2 = count1<count2?count1:count2;
	if(ans2>0) printf("%d",ans+ans2-1);
	else printf("%d",ans-1);
}