题意:给定一个n*n的棋盘,棋盘中的'X’代表障碍物,'.'代表空地,问在空地上最多放多少车,使得它们不会互相攻击。
分析:由于n比较小,应该可以直接暴力,这里用的二分匹配的方法。
建图:先扫描行,连通的格子看成一个结点,这样可以得到二分图的X部,再同样扫描列,得到Y部,有公共方格的结点连边,然后求最大匹配就是结果。
正确性分析:扫描行得到的结点之间不可能有公共方格,所以X部的结点内部没有连边,同理Y部的结点内部结点没有连边,所以建立的图是二部图。每个结点内最多只能放一个车,有公共方格的结点最多只能选取其中一个放车,这样就得到一个最大匹配的模型。
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
#include <stdio.h> #include <string.h> #define N 16 char map[5][5]; int idx[5][5],idy[5][5]; int n; int g[N][N]; int x[N],y[N],cnt1,cnt2; int vis[N]; 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 i,ret=0; memset(x,-1,sizeof(x)); memset(y,-1,sizeof(y)); for(i=1;i<=cnt1;i++) { memset(vis,0,sizeof(vis)); if(x[i]==-1) ret+=path(i); } return ret; } void build() { int i,j; cnt1=0; for(i=0;i<n;i++) { for(j=0;j<n;j++) if(map[i][j]=='.') { if(j==0 || map[i][j-1]!='.') cnt1++; idx[i][j]=cnt1; } } cnt2=0; for(j=0;j<n;j++) { for(i=0;i<n;i++) if(map[i][j]=='.') { if(i==0 || map[i-1][j]!='.') cnt2++; idy[i][j]=cnt2; } } memset(g,0,sizeof(g)); for(i=0;i<n;i++) { for(j=0;j<n;j++) if(map[i][j]=='.') g[idx[i][j]][idy[i][j]]=1; } } int main() { int i; while(scanf("%d",&n),n) { for(i=0;i<n;i++) scanf("%s",map[i]); build(); printf("%d\n",maxmatch()); } return 0; }