#include<bits/stdc++.h>
#define inf 2000000000
#define eb emplace_back
#define pb push_back
#define fi first
#define se second
#define fastio ios::sync_with_stdio(false);cin.tie(NULL)
#define rng_23 mt19937 rng(chrono::steady_clock::now().time_since_epoch().count())
using namespace std;
typedef long long ll;
typedef pair<int,int> pii;
typedef vector<int> vi;
typedef vector<pair<int,int>> vii;
typedef set<int> si;
typedef multiset<int> msi;
typedef map<int,int> mii;
int grid[1001][1001],reps[1001][1001];
pii parent[1001][1001];
pii rep(pii a)
{
    if(parent[a.fi][a.se]==a)
        return a;
    return  parent[a.fi][a.se]=rep(parent[a.fi][a.se]);
}
int main()
{
    int i,j,k;
    int n,m;
    string str;
    cin>>n>>m;
    for(i=1;i<=n;i++){
        cin>>str;
        for(j=1;j<=m;j++){
            grid[i][j]=str[j-1];
            parent[i][j]=make_pair(i,j);
        }

    }
    grid[1][1]='#';
    grid[1][m]='#';
    grid[n][1]='#';
    grid[n][m]='#';
    int r=0,c=0;
    for(i=1;i<=n;i++){
        int sig=1;
        for(j=1;j<=m;j++)
            if(grid[i][j]=='#')
                sig=0;
        r+=sig;
        if(sig)
            grid[i][1]='*';
    }
    for(j=1;j<=m;j++){
        int sig=1;
        for(i=1;i<=n;i++)
            if(grid[i][j]=='#')
                sig=0;
        c+=sig;
        if(sig)
            grid[1][j]='*';
    }
    //cout<<r<<" "<<c<<endl;
    if(r<c){
        for(j=1;j<=m;j++)
            if(grid[1][j]=='*')
                grid[1][j]='.';

    }
    else {
        for(i=1;i<=n;i++)
            if(grid[i][1]=='*')
                grid[i][1]='.';
    }
    for(i=1;i<=n;i++){
        vii vec;
        for(j=1;j<=m;j++)
            if(grid[i][j]=='#' || grid[i][j]=='*')
                vec.pb(make_pair(i,j));
        pii lrp;
        if(!vec.empty())
            lrp=rep(vec.front());
        for(j=1;j<vec.size();j++){
            pii rp=rep(vec[j]);
            parent[rp.fi][rp.se]=lrp;
        }
    }
    for(j=1;j<=m;j++){
        vii vec;
        for(i=1;i<=n;i++)
            if(grid[i][j]=='#' || grid[i][j]=='*')
                vec.pb(make_pair(i,j));
        pii lrp;
        if(!vec.empty())
            lrp=rep(vec.front());
        for(i=1;i<vec.size();i++){
            pii rp=rep(vec[i]);
            parent[rp.fi][rp.se]=lrp;
        }
    }
    //cout<<"hola"<<endl;
    set<pii> cnt;
    for(i=1;i<=n;i++)
        for(j=1;j<=m;j++)
            if(grid[i][j]=='#' || grid[i][j]=='*')
                cnt.insert(rep(make_pair(i,j)));
    cout<<cnt.size()-1+min(r,c)<<endl;
    //cout<<rep(make_pair(7,2)).fi<<" "<<rep(make_pair(7,2)).se<<endl;
}


#include <iostream>
#include <vector>
#include <algorithm>
#include<numeric>
#include<unordered_map>

using namespace std;

#define MP make_pair
#define PB push_back
#define REP(i, L, R) for (int i = L; i < (R); ++i)
#define SZ(x) (int)x.size()

using ll = long long;
using ii = pair<int,int>;

struct DSU {
    int n;
    // p[i] := rep of the component of i.
    vector<int> p;
    // rank[i] := size of the component of i.
    vector<int> rank;

    void init(int sz) {
        n = sz;
        p.resize(n);
        iota(p.begin(), p.end(), 0);
        rank.assign(n,1);
    }

    int getRep(int i) {
        if(p[i] == i) {
            return i;
        }
        return p[i] = getRep(p[i]);
    }

    bool same(int x, int y) {
        return getRep(x) == getRep(y);
    }

    bool merge(int x, int y) {
        x = getRep(x);
        y = getRep(y);
        if(x == y) {
            return false;
        }
        if(rank[x] < rank[y]) {
            swap(x, y);
        }
        rank[x] += rank[y];
        p[y] = x;
        return true;
    }
};


int main()
{
    int h, w;
    cin >> h >> w;
    // Consider bipartite graph: vertices represent rows 0,...h-1 
    // and cols h,...h+w-1; and edges between rows and columns.
    vector<ii> edges;

    vector<string> s(h);
    REP(i, 0, h) {
        cin >> s[i];
        REP(j, 0, w) {
            if(s[i][j] == '#') {
                edges.emplace_back(i, j+h);
            }
        } 
    } 
    // row 0 <-> col 0 (indexed as vertex h)
    edges.emplace_back(0, h);
    // row 0 <-> col w-1 (last col)
    edges.emplace_back(0, h+w-1);
    // row h-1 (last row) <-> col 0
    edges.emplace_back(h-1, h);
    // row h-1 <-> col w-1
    edges.emplace_back(h-1, h+w-1);
    
    DSU dsu;
    dsu.init(h+w);
    for(auto e: edges) {
        dsu.merge(e.first, e.second);
    }

    unordered_map<int, bool> comp;
    int cc = 0;
    REP(i, 0, h) {
        int c = dsu.getRep(i);
        if(!comp[c]) {
            ++cc;
            comp[c] = true;
        } 
    }
    int ans = cc-1;

    comp.clear();
    cc = 0;
    REP(i, h, h+w) {
        int c = dsu.getRep(i);
        if(!comp[c]) {
            ++cc;
            comp[c] = true;
        }
    }
    ans = min(ans, cc-1);
    
    cout << ans << endl;
    
    return 0;
}
