题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1045
解题思路:
首先,这题的数据范围很小,可以暴搜,略过不表。此处主要讲二分匹配作法。
思路来源于网络。
对于同一行上没有石头相隔的相连格子,我们将其编成一个号,得到一个号码集合X;同一列上没有石头相隔的相连格子也编成一个号,得到另一个号码集合Y。X,Y中的每个号码就代表某一个或者几个格子,如果X中的一个号码对应的格子和Y中的一个号码对应的格子有重叠,那么就记这两个号码相匹配。最后只要求出X和Y的最大匹配数即可得出答案。
图片来源于:http://blog.csdn.net/job_yi/article/details/10172925
AC代码:
1 #include <iostream> 2 #include <cstring> 3 #include <cstdio> 4 using namespace std; 5 char Map[5][5]; 6 int x[5][5],y[5][5]; 7 bool link[20][20],vis[20]; 8 int y_x[20]; 9 int n; 10 int xi,yi; 11 bool finds(int x){ 12 for(int i=1;i<=yi;i++){ 13 if(link[x][i]&&!vis[i]){ 14 vis[i]=true; 15 if(y_x[i]==0||finds(y_x[i])){ 16 y_x[i]=x; 17 return true; 18 } 19 } 20 } 21 return false; 22 } 23 int main(){ 24 while(scanf("%d",&n)==1&&n){ 25 memset(y_x,0,sizeof(y_x)); 26 memset(link,0,sizeof(link)); 27 memset(x,0,sizeof(x)); 28 memset(y,0,sizeof(y)); 29 for(int i=0;i<n;i++) scanf("%s",Map[i]); 30 xi=yi=0; 31 bool used=true; 32 for(int i=0;i<n;i++){ 33 if(used){ 34 xi++; used=false; 35 } 36 for(int j=0;j<n;j++){ 37 if(Map[i][j]=='X'&&used){ 38 used=false; 39 xi++; 40 } 41 else if(Map[i][j]=='.'){ 42 x[i][j]=xi; used=true; 43 } 44 } 45 if(i==n-1&&!used) xi--; 46 } 47 used=true; 48 for(int j=0;j<n;j++){ 49 if(used){ 50 yi++; used=false; 51 } 52 for(int i=0;i<n;i++){ 53 if(Map[i][j]=='X'&&used){ 54 yi++; used=false; 55 } 56 else if(Map[i][j]=='.'){ 57 y[i][j]=yi; used=true; 58 } 59 } 60 if(j==n-1&&!used) yi--; 61 } 62 for(int i=0;i<n;i++){ 63 for(int j=0;j<n;j++){ 64 link[x[i][j]][y[i][j]]=true; 65 } 66 } 67 int ans=0; 68 for(int i=1;i<=xi;i++){ 69 memset(vis,0,sizeof(vis)); 70 if(finds(i)) ans++; 71 } 72 printf("%d\n",ans); 73 } 74 return 0; 75 }