zoj1654
Robert is a famous engineer. One day he was given a task by his boss. The background of the task was the following:
Given a map consisting of square blocks. There were three kinds of blocks: Wall, Grass, and Empty. His boss wanted to place as many robots as possible in the map. Each robot held a laser weapon which could shoot to four directions (north, east, south, west) simultaneously. A robot had to stay at the block where it was initially placed all the time and to keep firing all the time. The laser beams certainly could pass the grid of Grass, but could not pass the grid of Wall. A robot could only be placed in an Empty block. Surely the boss would not want to see one robot hurting another. In other words, two robots must not be placed in one line (horizontally or vertically) unless there is a Wall between them.
Now that you are such a smart programmer and one of Robert's best friends, He is asking you to help him solving this problem. That is, given the description of a map, compute the maximum number of robots that can be placed in the map.
Input
The first line contains an integer T (<= 11) which is the number of test cases.
For each test case, the first line contains two integers m and n (1<= m, n <=50) which are the row and column sizes of the map. Then m lines follow, each contains n characters of '#', '*', or 'o' which represent Wall, Grass, and Empty, respectively.
Output
For each test case, first output the case number in one line, in the format: "Case :id" where id is the test case number, counting from 1. In the second line just output the maximum number of robots that can be placed in that map.
Sample Input
2
4 4
o***
*###
oo#o
***o
4 4
#ooo
o#oo
oo#o
***#
Sample Output
Case :1
3
Case :2
5
#include <cstdio> #include <cstring> #define MAX 51 int m, n; //地图的大小m*n,(1<= m, n <=50) char map[MAX][MAX]; //地图 int x[MAX*MAX], y[MAX*MAX]; //x[i]表示与Xi匹配的Y顶点,y[i]表示与Yi匹配的X顶点 int xs[MAX][MAX], ys[MAX][MAX]; //水平方向上"块"的编号,垂直方向上"块"的编号 int xn, yn1; //水平方向上的"块"个数、垂直方向上的"块"个数 //对水平方向上和垂直方向上的块进行连接(若两个块有公共的空地,则在它们之间连边) //如果g[i][j]==1,那么水平方向上的第i个块跟垂直方向上的第j个块有公共的空地 bool g[MAX*MAX][MAX*MAX]; //DFS算法中记录顶点访问的状态,如果t[i]=0表示未访问过,如果为1表示访问过 int t[MAX*MAX]; //从X集合中的顶点u出发用深度优先策略寻找增广路 //(这种增广路只能使当前的匹配数增加1) bool path( int u ) { int v; for( v=1; v<=yn1; v++ ) //考虑所有Yi顶点 { if( g[u][v] && !t[v] ) //v跟u邻接并且v未访问过 { t[v] = 1; //如果v没有匹配, //或者如果v已经匹配了,但从y[v]出发可以找到一条增广路 if( !y[v] || path(y[v]) ) { x[u]=v; y[v]=u; //把v匹配给u, 把u匹配给v return 1; } } } return 0; //如果不存在从u出发的增广路 } void MaxMatch( ) //求二部图的最大匹配算法 { int i, ans = 0; //最大匹配数 memset( x, 0, sizeof(x) ); memset( y, 0, sizeof(y) ); //从0匹配开始增广 for( i=1; i<=xn; i++ ) { if( !x[i] ) //从每个未盖点出发进行寻找增广路 { memset( t, 0, sizeof(t) ); if( path(i) ) //每找到一条增广路,可使得匹配数加1 ans++; } } printf( "%d\n", ans ); } int main( ) { int k, kase;//case的个数 int i, j; //循环变量 int number; //用来对水平方向和垂直方向上的"块"进行编号的序号 int flag; //一个"块"开始的标志 scanf( "%d", &kase ); for( k=0; k<kase; k++ ) { printf( "Case :%d\n", k+1 ); scanf( "%d%d", &m, &n ); //读入地图大小 memset( xs, 0, sizeof(xs) ); memset( ys, 0, sizeof(ys) ); for( i=0; i<m; i++ ) //读入地图 { scanf( "%s", map[i] ); } number = 0; //用来对水平方向和垂直方向上的"块"进行编号的序号 for( i=0; i<m; i++ ) //对水平方向上的块进行编号 { flag = 0; for( j=0; j<n; j++ ) { if( map[i][j]=='o' ) { if( flag==0 ) number++; xs[i][j] = number; flag = 1; } else if( map[i][j]=='#' ) flag = 0; } } xn = number; number = 0; for( j=0; j<n; j++ ) //对垂直方向上的块进行编号 { flag = 0; for( i=0; i<m; i++ ) { if( map[i][j]=='o' ) { if( flag==0 ) number++; ys[i][j] = number; flag = 1; } else if( map[i][j]=='#' ) flag = 0; } } yn1 = number; memset( g, 0, sizeof(g) ); for( i=0; i<m; i++ ) { for( j=0; j<n; j++ ) { //对水平方向上和垂直方向上的块进行连接 //(若两个块有公共的空地,则在它们之间连边) if( xs[i][j] ) g[xs[i][j]][ys[i][j]] = 1; } } MaxMatch( ); } return 0; }