明显的二分图匹配。

1元素、0要素都满足。

#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<cmath>
#include<ctime>
#include<vector>
#include<algorithm>
#define gc getchar()
#define ll long long
#define eps 1e-8
#define ld long double 
#define ull unsigned long long
using namespace std;
const int N=2505,M=N*N;
template<class o>
inline void qr(o &x)
{
    x=0;char c=gc;int f=1;
    while(c<'0'||c>'9'){if(c=='-')f=-1;c=gc;}
    while(c>='0'&&c<='9'){x=x*10+(c^48);c=gc;}
    x*=f;
}
template<class o>
void qw(o x)
{
    if(x<0)putchar('-'),x=-x;
    if(x/10)qw(x/10);
    putchar(x%10+48);
}
struct edge{int y,next;}a[M];int len,last[N];
void ins(int x,int y){a[++len]=(edge){y,last[x]};last[x]=len;}
int match[N];bool v[N];
bool find(int x)
{
    for(int k=last[x],y;k;k=a[k].next)
        if(!v[y=a[k].y])
        {
            v[y]=1;if(!match[y]||find(match[y])){match[y]=x;return 1;}
        }
    return 0;
}
bool vis[N][N];
int r[55][55],c[55][55];
char s[55][55];
int main()
{
    int n,m,l1=0,l2=0;qr(n),qr(m);
    for(int i=1;i<=n;i++)
        scanf("%s",s[i]+1);
    for(int i=1;i<=n;i++)
        for(int j=1;j<=m;j++)
        {
            if(s[i][j]=='#')continue;
            if(!r[i-1][j])r[i][j]=++l1;
            else r[i][j]=r[i-1][j];
            if(!c[i][j-1])c[i][j]=++l2;
            else c[i][j]=c[i][j-1];
        }
    for(int i=1;i<=n;i++)
        for(int j=1;j<=m;j++)
            if(r[i][j]&&c[i][j]&&s[i][j]!='x'&&!vis[r[i][j]][c[i][j]])
                vis[r[i][j]][c[i][j]]=1,ins(r[i][j],c[i][j]);
    int ans=0;
    for(int i=1;i<=l1;i++)
    {
        memset(v,0,sizeof(v));
        if(find(i))ans++;
    }
    qw(ans);puts("");
    return 0;
}