#include <bits/stdc++.h>

using namespace std;

typedef long long ll;
typedef pair<int, int> pi;

const int dy[4] = { -1, 0, 1, 0 }, dx[4] = { 0, 1, 0, -1 };

char mp[1000][1000];
vector<int> gph[2000];
bool chk[2000];

int main() {
	ios_base::sync_with_stdio(false);
	cin.tie(nullptr);

	int r, c;
	cin >> r >> c;
	gph[0].push_back(r);
	gph[r].push_back(0);
	gph[0].push_back(r + c - 1);
	gph[r + c - 1].push_back(0);
	gph[r - 1].push_back(r);
	gph[r].push_back(r - 1);
	gph[r - 1].push_back(r + c - 1);
	gph[r + c - 1].push_back(r - 1);
	for (int i = 0; i < r; ++i)
		for (int j = 0; j < c; ++j) {
			cin >> mp[i][j];
			if (mp[i][j] == '#') {
				gph[i].push_back(r + j);
				gph[r + j].push_back(i);
			}
		}

	int cnt0 = 0, cnt1 = 0;
	for (int i = 0; i < r + c; ++i)
		if (!chk[i]) {
			queue<int> q;
			chk[i] = true;
			q.push(i);
			
			bool chk0 = false, chk1 = false;
			while (!q.empty()) {
				int now = q.front();
				q.pop();

				if (now < r)
					chk0 = true;
				else
					chk1 = true;

				for (int nxt : gph[now])
					if (!chk[nxt]) {
						chk[nxt] = true;
						q.push(nxt);
					}
			}

			if (chk0)
				cnt0++;
			if (chk1)
				cnt1++;
		}

	cout << min(cnt0, cnt1) - 1;

	return 0;
}
#include <ext/pb_ds/assoc_container.hpp>
#include <ext/pb_ds/tree_policy.hpp>
#include <bits/stdc++.h>

using namespace __gnu_pbds;
using namespace std;

using ll = long long;
using ld = long double;

typedef tree<
        int,
        null_type,
        less<int>,
        rb_tree_tag,
        tree_order_statistics_node_update>
        ordered_set;

#define mp make_pair


const int p =  1e9 + 7;

int mul(int a, int b) {
    return (1LL * a * b) % p;
}

int add(int a, int b) {
    int s = (a+b);
    if (s>=p) s-=p;
    return s;
}

int sub(int a, int b) {
    int s = (a+p-b);
    if (s>=p) s-=p;
    return s;
}

int po(int a, ll deg)
{
    if (deg==0) return 1;
    if (deg%2==1) return mul(a, po(a, deg-1));
    int t = po(a, deg/2);
    return mul(t, t);
}

int inv(int n)
{
    return po(n, p-2);
}


mt19937 rnd(time(0));

/*
const int N = 1e6 + 5;

vector<int> facs(N), invfacs(N);

void init()
{
    facs[0] = 1;
    for (int i = 1; i<N; i++) facs[i] = mul(facs[i-1], i);
    invfacs[N-1] = inv(facs[N-1]);
    for (int i = N-2; i>=0; i--) invfacs[i] = mul(invfacs[i+1], i+1);
}

int C(int n, int k)
{
    if (n<k) return 0;
    if (n<0 || k<0) return 0;
    return mul(facs[n], mul(invfacs[k], invfacs[n-k]));
}*/


struct DSU
{
    vector<int> sz;
    vector<int> parent;
    void make_set(int v) {
        parent[v] = v;
        sz[v] = 1;
    }

    int find_set(int v) {
        if (v == parent[v])
            return v;
        else
        {
            auto par = find_set(parent[v]);
            parent[v] = par;
            return par;
        }
    }

    void union_sets(int a, int b) {
        find_set(a);
        find_set(b);

        a = find_set(a);
        b = find_set(b);

        if (a != b) {
            if (sz[a] < sz[b])
                swap(a, b);
            parent[b] = a;
            sz[a] += sz[b];
        }
    }
    DSU (int n)
    {
        parent.resize(n);
        sz.resize(n);
        for (int i = 0; i<n; i++) make_set(i);
    }
};


int main()
{
    ios_base::sync_with_stdio(0);
    cin.tie(nullptr);


    int H, W; cin>>H>>W;
    vector<string> a(H);
    for (int i = 0; i<H; i++) cin>>a[i];

    DSU dsu(H+W);
    for (int i = 0; i<H; i++) for (int j = 0; j<W; j++)
    {
        bool unite = true;
        if (i!=0 && i!=H-1) unite = false;
        if (j!=0 && j!=W-1) unite = false;
        if (a[i][j]=='#') unite = true;
        if (unite) dsu.union_sets(i, H+j);
    }

    int minn = 1e9;
    set<int> vert;
    for (int i = 0; i<H; i++) vert.insert(dsu.find_set(i));
    minn = min(minn, (int)vert.size() - 1);

    set<int> hor;
    for (int i = H; i<H+W; i++) hor.insert(dsu.find_set(i));
    minn = min(minn, (int)hor.size() - 1);

    cout<<minn;






}
