题目大意:给一个n*m的方格地图,每个方格中有一个字符,'.'草地,'*'泥巴地,给你一些宽为1方格大小的板子,长度不限,问最少需要多少板子才能盖住所有的泥巴地,但是不能盖住草地,板子允许相互覆盖。
分析:扫描行,将连通的泥巴地看成一个结点,这样得到二分图的X部,按同样的方法扫描列得到二分图的Y部,有公共方格的结点之间连边。
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
#include <stdio.h> #include <string.h> #define N 51 #define M 51 char map[N][M]; bool g[N*M][N*M]; int n,m; int x[N*M],y[N*M],vis[N*M]; int a[N][M],b[N][M],cnt1,cnt2; void build() { int i,j; cnt1=0; for(i=0;i<n;i++) { for(j=0;j<m;j++) if(map[i][j]=='*') { if(j==0 || map[i][j-1]!='*') cnt1++; a[i][j]=cnt1; } } cnt2=0; for(j=0;j<m;j++) { for(i=0;i<n;i++) if(map[i][j]=='*') { if(i==0 || map[i-1][j]!='*') cnt2++; b[i][j]=cnt2; } } memset(g,0,sizeof(g)); for(i=0;i<n;i++) { for(j=0;j<m;j++) if(map[i][j]=='*') { g[a[i][j]][b[i][j]]=1; } } } int path(int u) { for(int v=1;v<=cnt2;v++) if(g[u][v] && !vis[v]) { vis[v]=1; if(y[v]==-1 || path(y[v])) { x[u]=v; y[v]=u; return 1; } } return 0; } int maxmatch() { int ret=0; memset(x,-1,sizeof(x)); memset(y,-1,sizeof(y)); for(int u=1;u<=cnt1;u++) { memset(vis,0,sizeof(vis)); if(x[u]==-1) ret+=path(u); } return ret; } int main() { int i; while(~scanf("%d%d",&n,&m)) { for(i=0;i<n;i++) scanf("%s",map[i]); build(); printf("%d\n",maxmatch()); } return 0; }