ZJU 1654 Place the Robots(二分图)
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
http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemId=654
算法:不要用搜索来解这道题,可以灵活运用二分图的想法,构造邻接矩阵。。将横着的没有被阻挡的块合并成一个大块。将竖着的没有被阻挡的块合并成一个大块。这样得到若干个横向块,和纵向块,如果一横向块与纵向块之间有共同的点,那么就将这两个大块连线(构造一个横向块与纵向块的邻接矩阵)。构造好之后就可以算横向块与纵向块的最大匹配数。这个数就是机器人的可以摆放的个数。。
代码:
#include <iostream>
using namespace std;
struct XBlock
{
int x;
int starty, endy;
};
struct YBlock
{
int y;
int startx, endx;
};
XBlock bx[2501];
YBlock yb[2501];
char map[51][51];
char temp[51][51];
int casen, n, m, bxn, byn, match;
bool connect[2501][2501];
bool state[1501];
int res[1501];
void copy()
{
int i,j;
for( i = 1; i <= n ; i++)
for( j = 1; j <= m; j++)
temp[i][j] = map[i][j];
}
void MakeXBlock()
{
int i, j, t;
bxn = 0; //记录bx[]的下标
for( i = 1; i <= n ; i++)
for( j = 1; j <= m; j++)
if(temp[i][j] == 'o')
{
bxn ++;
bx[bxn].x = i;
for( t = j; t > 0; t--)//确定横向块的起始坐标
{
if(temp[i][t] == '#')
{
bx[bxn].starty = t+1;
break;
}
else
{
bx[bxn].starty = t;
if(temp[i][t] == 'o' && t != j) //删除这一块中的其他‘o’
temp[i][t] = 'x';
}
}
for( t = j; t <= m; t++ )//确定横向块的结束坐标
{
if(temp[i][t] == '#')
{
bx[bxn].endy = t-1;
break;
}
else
{
bx[bxn].endy = t;
if(temp[i][t] == 'o' && t != j ) //删除这一块中的其他‘o’
temp[i][t] = 'x';
}
}
}
}
void MakeYBlock()
{
int i, j, t;
byn = 0;
for(j = 1; j <= m ;j++)
for(i = 1; i <= n; i++)
if(temp[i][j] == 'o')
{
byn++;
yb[byn].y = j;
for(t = i ; t > 0 ; t--) //确定纵向块的起始坐标
{
if(temp[t][j] == '#')
{
yb[byn].startx = t+1;
break;
}
else
{
yb[byn].startx = t;
if(temp[t][j] == 'o' && t != i) //删除这一块中的其他‘o’
temp[t][j] = 'x';
}
}
for( t = i; t <= n; t++ )//确定纵向快的结束坐标
{
if(temp[t][j] == '#')
{
yb[byn].endx = t-1;
break;
}
else
{
yb[byn].endx = t;
if(temp[t][j] == 'o' && t != i ) //删除这一块中的其他‘o’
temp[t][j] = 'x';
}
}
}
}
bool find(int i) //匈牙利算法,进行最大匹配计算
{
int j;
for(j = 1; j <= byn; j++)
if(connect[i][j] == true && state[j] == false)
{
state[j] = true;
if(res[j] == 0 || find (res[j]) == true)
{
res[j] = i;
return true;
}
}
return false;
}
for( i = 1; i <= 1500; i++) // 初始化结构体里的坐标 }
int main()
{
cin>>casen;
int i, j, num = casen;
while(num--)
{
cin>>n>>m;
for( i = 1; i <= n ; i++)
for( j = 1; j <= m; j++)
cin>>map[i][j];
{
bx[i].endy = bx[i].starty = bx[i].x = 0;
yb[i].endx = yb[i].startx = yb[i].y = 0;
}
copy();
MakeXBlock();//构造横向块
copy();
MakeYBlock(); //构造纵向块
memset(connect, false, sizeof(connect));
memset(res, 0 , sizeof(res));
for(i = 1; i <= bxn; i++) //构造邻接矩阵
for(j = 1; j <= byn; j++)
{
if((bx[i].x >= yb[j].startx && bx[i].x <= yb[j].endx) &&( yb[j].y >= bx[i].starty && yb[j].y <= bx[i].endy ) && map[bx[i].x][yb[j].y] == 'o')
connect[i][j] = true;
}
match = 0;
for(i = 1; i <= bxn; i++) //计算最大匹配数
{
memset(state, false, sizeof(state));
if(find(i))
match++;
}
cout<<"Case :"<<casen- num<<endl;
cout<<match<<endl;
return 0;
}
不要忽略了横块和竖块之间虽然有共同块,但该共同块却是草地,不能放robot,所以要将其可能性排除