二分图的最小边覆盖=n-最大匹配
#include<cstdio> #include<cstring> #include<cmath> #include<algorithm> using namespace std; char Map[45][15]; int r[45][15];//给*标号 int c[45][15];//处理奇偶性 int w,h,tot; const int MAXN=505; int nx,ny; int g[MAXN][MAXN]; int cx[MAXN],cy[MAXN]; int mk[MAXN]; int n; int path(int u) { for(int v=0; v<ny; v++) { if(g[u][v]&&!mk[v]) { mk[v]=1; if(cy[v]==-1||path(cy[v])) { cx[u]=v; cy[v]=u; return 1; } } } return 0; } int MaxMatch() { int res=0; memset(cx,-1,sizeof(cx)); memset(cy,-1,sizeof(cy)); for(int i=0; i<nx; i++) { if(cx[i]==-1) { memset(mk,0,sizeof(mk)); res=res+path(i); } } return res; } int main() { for(int i=0; i<=10; i++) { if(i%2==0) c[0][i]=0; else c[0][i]=1; } for(int i=1; i<=40; i++) for(int j=0; j<=10; j++) c[i][j]=1-c[i-1][j]; int T; scanf("%d",&T); while(T--) { scanf("%d%d",&h,&w); tot=1; memset(r,-1,sizeof r); for(int i=0; i<h; i++) scanf("%s",Map[i]); for(int i=0; i<h; i++) for(int j=0; j<w; j++) if(Map[i][j]=='*') r[i][j]=tot,tot++; nx=tot,ny=tot; memset(g,0,sizeof(g)); for(int i=0; i<h; i++) for(int j=0; j<w; j++) if(Map[i][j]=='*') { if(c[i][j]%2==1) //是奇数 { if(Map[i+1][j]=='*') g[r[i][j]][r[i+1][j]]=1; if(Map[i][j+1]=='*') g[r[i][j]][r[i][j+1]]=1; } else //是偶数 { if(Map[i+1][j]=='*') g[r[i+1][j]][r[i][j]]=1; if(Map[i][j+1]=='*') g[r[i][j+1]][r[i][j]]=1; } } printf("%d ", tot-1-MaxMatch()); } return 0; }