#include<iostream>
#include<set>
#include<vector>
using namespace std;
typedef long long li;
#define rep(i,n) for(int i=0;i<(n);i++)
#define df 0
template<class T> void print(const T& t){ cout << t << "\n"; }
template<class T, class... Ts> void print(const T& t, const Ts&... ts) { cout << t; if (sizeof...(ts)) cout << " "; print(ts...); }

int find(int a,vector<int>& uf){
  if(uf[a]<0) return a;
  return uf[a]=find(uf[a],uf);
}

void unite(int a,int b,vector<int>& uf){
  a=find(a,uf),b=find(b,uf);
  if(a==b)return ;
  if(uf[a]>uf[b]) swap(a,b);
  uf[a]+=uf[b];
  uf[b]=a;
}

int main(){
  int h,w; cin >>h >>w;
  vector<string> mp(h); rep(i,h) cin >>mp[i];
  vector<vector<int>> adj(h+w);
  int n=h+w;
  vector<int> uf(n,-1);
  unite(0,h,uf);
  unite(h-1,h,uf);
  unite(h-1,h+w-1,uf);
  unite(0,h+w-1,uf);
  rep(i,h) rep(j,w){
    if(mp[i][j]=='#'){
      unite(i,h+j,uf);
    }
  }
  
  set<int> tate,yoko;
  rep(i,h){
    tate.insert(find(i,uf));
  }
  rep(j,w){
    yoko.insert(find(h+j,uf));
  }
  print(min(tate.size(),yoko.size())-1);
}

#include "iostream"
#include "climits"
#include "list"
#include "queue"
#include "stack"
#include "set"
#include "functional"
#include "algorithm"
#include "string"
#include "map"
#include "unordered_map"
#include "unordered_set"
#include "iomanip"
#include "cmath"
#include "random"
#include "bitset"
#include "cstdio"
#include "numeric"
#include "cassert"
#include "ctime"

using namespace std;

constexpr long long int MOD = 1000000007;
//constexpr int MOD = 1000000007;
//constexpr int MOD = 998244353;
//constexpr long long int MOD = 998244353;
constexpr double EPS = 1e-8;

//int N, M, K, T, H, W, L, R;
long long int N, M, K, T, H, W, L, R;

class UnionFind {
	vector<int>parent;
	vector<int>rank;
public:
	UnionFind(int num) {
		num++;
		parent.resize(num);
		rank.resize(num);
		for (int i = 0; i < num; i++) {
			parent[i] = i;
			rank[i] = 0;
		}
	}
	int Find(int node) {
		if (parent[node] == node)return node;
		else return parent[node] = Find(parent[node]);
	}
	void Unite(int u, int v) {
		u = Find(u);
		v = Find(v);
		if (u == v)return;
		if (rank[u] < rank[v])parent[u] = v;
		else {
			parent[v] = u;
			if (rank[u] == rank[v])rank[u]++;
		}
	}
	bool Check_Same(int u, int v) {
		return Find(u) == Find(v);
	}
};

int Solve(vector<string>s) {
	H = s.size();
	W = s[0].size();
	UnionFind uf(H);
	uf.Unite(0, H - 1);
	vector<vector<int>>w(W);
	w[0].push_back(0);
	w[0].push_back(H - 1);
	w[W - 1].push_back(0);
	w[W - 1].push_back(H - 1);
	for (int i = 0; i < H; i++) {
		for (int j = 0; j < W; j++) {
			if (s[i][j] == '#') {
				w[j].push_back(i);
			}
		}
	}
	int ret = H - 2;
	for (int i = 0; i < W; i++) {
		for (int j = 1; j < w[i].size(); j++) {
			if (uf.Check_Same(w[i][j], w[i][0]))continue;
			ret--;
			uf.Unite(w[i][j], w[i][0]);
		}
	}
	return ret;
}

int main() {
	ios::sync_with_stdio(false);
	cin.tie(0);

	cin >> H >> W;
	vector<string>s(H);
	for (auto &i : s) cin >> i;
	int ans = MOD;
	ans = min(ans, Solve(s));
	vector<string>t(s[0].size());
	for (int i = 0; i < H; i++) {
		for (int j = 0; j < W; j++) {
			t[j].push_back(s[i][j]);
		}
	}
	cout << min(ans, Solve(t)) << endl;
}