#include <bits/stdc++.h>
using namespace std;

const int N = 2005;

int n, m, fa[N], ans1, ans2, siz[N]; 
char a[N][N];

int find_(int x) {
	return x == fa[x] ? x : fa[x] = find_(fa[x]);
}

int main() {
	scanf("%d%d", &n, &m);
	for (int i = 1; i <= n + m; i++)
		fa[i] = i, siz[i] = 1;
	for (int i = 1; i <= n; i++)
		scanf("%s", a[i] + 1);
	a[1][1] = a[n][1] = a[1][m] = a[n][m] = '#';
	for (int i = 1; i <= n; i++)
		for (int j = 1; j <= m; j++)
			if (a[i][j] == '#') {
				int x = find_(i), y = find_(j + n);
				if (x^y)
					fa[x] = y, siz[y] += siz[x];
			}
	for (int i = 1; i <= n + m; i++)
		if (find_(i) == i)
			ans1 += (i <= n)|(siz[i] >= 2), ans2 += (i > n)|(siz[i] >= 2);
	printf("%d\n", min(ans1, ans2) - 1);
}
#include "bits/stdc++.h"
#include <ext/pb_ds/assoc_container.hpp>
#include <ext/pb_ds/tree_policy.hpp>

using namespace std;
using namespace __gnu_pbds;

#define all(x)  x.begin(), x.end()
#define sz(x)   (int)x.size()
#define pb      push_back

#define ll      long long
#define int     long long

template <typename T>
using ordered_set = tree<T, null_type,
      less<T>, rb_tree_tag,
      tree_order_statistics_node_update>;

const int MOD1 = 1000000007;
const int MOD2 = 998244353;
const int N = 2e6 + 10;

#ifdef LOCAL
	#include "debug.h"
#else
	#define trace(...) 420;
#endif

struct DSU
{
	int32_t _parent_[N], _rank_[N], _size_[N], comp = 0;

	void make_set(int32_t v) {
		_parent_[v] = v;
		_rank_[v] = 0;
		_size_[v] = 1;
		comp++;
	}
	void init(int32_t n) {
		for (int32_t i = 0; i < n; ++i) {
			make_set(i);
		}
	}
	int32_t find_set(int32_t v) {
		if (v == _parent_[v]) {
			return v;
		}
		return _parent_[v] = find_set(_parent_[v]);
	}
	void merge(int32_t a, int32_t b) {
		a = find_set(a);
		b = find_set(b);
		if (a != b) {
			if (_rank_[a] < _rank_[b]) {      //merge by height
				swap(a, b);
			}
			_parent_[b] = a;
			if (_rank_[a] == _rank_[b]) {
				_rank_[a]++;
			}

			// if (_size_[a] < _size_[b])            //merge by size
			//     swap(a, b);
			// _parent_[b] = a;
			_size_[a] += _size_[b];
			comp--;
		}
	}
} dsu;

vector<int> R[1001], C[1001];
vector<int> out;

void solve() {
	int h, w;
	cin >> h >> w;

	if (h == 2 || w == 2) {
		cout << 0;
		return;
	}

	string rink[h];
	dsu.init(h * w);
	int useless = 0;
	for (int i = 0; i < h; ++i) {
		cin >> rink[i];
		for (int j = 0; j < w; ++j) {
			if (rink[i][j] == '#') {
				R[i].pb(i * w + j);
				C[j].pb(i * w + j);
				if (i == 0 || i == h - 1) {
					out.pb(i * w + j);
				}
			} else {
				useless++;
			}
		}
		if (rink[i][0] == '#') { out.pb(i * w); }
		if (rink[i][w - 1] == '#') { out.pb(i * w + w - 1); }

	}

	int er = 0;
	for (int i = 0; i < h; ++i) {
		if (i && i != h - 1) { er += R[i].empty(); }
		for (int t : R[i]) {
			dsu.merge(t, R[i][0]);
		}
	}
	int ec = 0;
	for (int i = 0; i < w; ++i) {
		if (i && i != w - 1) { ec += C[i].empty(); }
		for (int t : C[i]) {
			dsu.merge(t, C[i][0]);
		}
	}
	for (int t : out) {
		dsu.merge(t, out[0]);
	}
	int x = min(er, ec);
	if (sz(out) == 0) { if (x == 0) { x = 1; } dsu.comp++; }
	cout << x + max(0LL, dsu.comp - useless - 1);
	// trace(er, ec, dsu.comp - useless);

}

int32_t main() {
	ios_base::sync_with_stdio(false);
	cin.tie(nullptr);
	cout.tie(nullptr);
	int t = 1;
	// cin >> t;
	while (t--) {
		solve();
		cout << '\n';
	}
	return 0;
}