传送门biu~
建图类似于【bzoj 1693】【bzoj 1741】Asteroids
对于每块泥地,求出能覆盖它的最长的横木板和纵木板。求最小顶点覆盖即可。
#include<bits/stdc++.h>
using namespace std;
const int INF=1e9;
int n,m,S,T;
char c[55][55];
int x[55][55],tpx,y[55][55],tpy;
int head[5005],fir[5005],dep[5005],nex[20005],to[20005],cap[20005],tp=1;
inline void add(int x,int y,int c){
nex[++tp]=head[x];
head[x]=tp;
to[tp]=y;
cap[tp]=c;
}
inline void Insert(int u,int v){add(u,v,1);add(v,u,0);}
inline int bfs(){
memset(dep,0,sizeof(dep));
dep[S]=1;queue<int>q;
q.push(S);
while(!q.empty()){
int x=q.front();q.pop();
for(int i=head[x];i;i=nex[i]){
if(cap[i] && !dep[to[i]]){
dep[to[i]]=dep[x]+1;
q.push(to[i]);
}
}
}
return dep[T];
}
int dfs(int x,int now){
if(x==T || !now) return now;
int c=0;
for(int &i=fir[x];i;i=nex[i]){
if(dep[to[i]]==dep[x]+1 && cap[i]){
int f=dfs(to[i],min(now,cap[i]));
now-=f;
cap[i]-=f;
cap[i^1]+=f;
c+=f;
if(!now) break;
}
}
return c;
}
inline int Dinic(){
int c=0;
while(bfs()){
for(int i=S;i<=T;++i) fir[i]=head[i];
c+=dfs(S,INF);
}
return c;
}
int main(){
scanf("%d%d",&n,&m);
for(int i=1;i<=n;++i) scanf("%s",c[i]+1);
for(int i=1;i<=n;++i){
for(int j=1;j<=m;++j){
if(c[i][j]=='.') continue;
if(c[i-1][j]==c[i][j]) y[i][j]=y[i-1][j];
else y[i][j]=++tpy;
if(c[i][j-1]==c[i][j]) x[i][j]=x[i][j-1];
else x[i][j]=++tpx;
}
}
S=0,T=tpx+tpy+1;
for(int i=1;i<=tpx;++i) Insert(S,i);
for(int i=1;i<=tpy;++i) Insert(tpx+i,T);
for(int i=1;i<=n;++i)
for(int j=1;j<=m;++j)
if(c[i][j]=='*') Insert(x[i][j],tpx+y[i][j]);
printf("%d",Dinic());
return 0;
}