和一般的题不太一样的地方在于:有了硬石头
那就分别计算行和列中连通块(以两块硬石头为分界)的个数,并连边,最大匹配
#include<cstdio>
#include<iostream>
#include<cstring>
#define For(i,j,k) for(int i=j;i<=k;i++)
using namespace std;
const int N=100+5;
int q[N][N];
int b[N][N];
char s[N][N];
int vis[N*N],w[N*N];
int n,m;
struct node{
int next;
int to;
}a[N*N];
int h[N*N],cnt;
void addvage(int x,int y){
cnt++;a[cnt].next=h[x];a[cnt].to=y;h[x]=cnt;
}
int hunger(int x){
for(int i=h[x];i;i=a[i].next){
int y=a[i].to;
if(vis[y])continue;
vis[y]=1;
if(w[y]==-1||hunger(w[y])){
w[y]=x;
return 1;
}
}
return 0;
}
int main(){
cin>>n>>m;
For(i,1,n)scanf("%s",s[i]+1);
int tx=0,ty=0;
For(i,1,n){
tx++;
For(j,1,m){
if(s[i][j]=='#')tx++;
q[i][j]=tx;
}
}
For(j,1,m){
ty++;
For(i,1,n){
if(s[i][j]=='#')ty++;
b[i][j]=ty;
}
}
For(i,1,n)
For(j,1,m)
if(s[i][j]=='*')
addvage(q[i][j],b[i][j]);
For(i,1,b[n][m])w[i]=-1;
int ans=0;
For(i,1,q[n][m]){
memset(vis,0,sizeof(vis));
ans+=hunger(i);
}
cout<<ans;
return 0;
}