ZOJ1654 place the robots(二分图匹配)

Mem:32MB   time:5s

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


题目意思和火力网差不多,但是新引入了草地(grass),机器人的攻击可以跨过草地但是不能把机器人放在上面。但是建图的时候注意,每一个联通块要包括草坪,但是只能将交点为空地的纵横联通块之间连边。代码是以两年前写的火力网为蓝本打的,所以风格还是很丑。。但还是稍微有点长进。。


#include<cstdio>
#include<cstring>
using namespace std;
#define MAXN 3000
#define clear(a) memset(a,0,sizeof a)
int T, n, m;
int xn, yn; //横向和纵向联通块的数目
char mat[60][60];
int xp[MAXN][3];//横向联通块所在的行,起始的位置,结束的位置
int yp[MAXN][3];

void init()
{
	int i, j, st;
	bool flag; //当前是否走在一个联通块中
	for (i = 1; i<=n; ++i)
		scanf("%s", mat[i]+1);
	for (i = 1; i<=n; ++i) {
		st = 1; flag = 0;
		for (j = 1; j<=m+1; ++j) {
			if (mat[i][j]=='o' && !flag)
				st = j, flag = 1;
			if ((mat[i][j]=='#'||j==m+1) && flag) {
				++xn;
				xp[xn][0] = i;
				xp[xn][1] = st;
				xp[xn][2] = j-1;
				flag = 0;
			}
		}
	}
	for (j = 1; j<=m; ++j) {
		st = 1; flag = 0;
		for (i = 1; i<=n+1; ++i) {
			if (mat[i][j]=='o' && !flag)
				st = i, flag = 1;
			if ((mat[i][j]=='#'||i==n+1) && flag) {
				++yn;
				yp[yn][0] = j;
				yp[yn][1] = st;
				yp[yn][2] = i-1;
				flag = 0;
			}
		}
	}
}

struct Node { int to; Node*next; };
struct BiGraph {//二分图结构体
    int match[MAXN], xn;
    bool vis[MAXN];
    Node Edge[MAXN*10], *ecnt, *adj[MAXN];
    BiGraph() { memset(adj,0,sizeof adj); ecnt=Edge; }
    void addedge(int a, int b)
    {
		++ecnt;
		ecnt->to = b;
		ecnt->next = adj[a];
		adj[a] = ecnt;
    }
    bool dfs(int u)//匈牙利算法
    {
		for (Node*p = adj[u]; p; p=p->next) {
			int &v = p->to;
			if (vis[v]) continue;
			vis[v] = 1;
			if (!match[v] || dfs(match[v])) {
				match[u] = v; match[v] = u;
                return 1;
			}
		}
		return 0;
    }
    int Maxmatch()
    {
		int ans = 0;
		for (int i = 1; i<=xn; ++i) 
			if (!match[i]) {
				memset(vis, 0, sizeof vis);
				ans += dfs(i);
			}
		return ans;
	}
} Empty, G;

inline bool CheckCross(int a, int b) { //判断两点是否需要连边
	if (xp[a][0] < yp[b][1] || xp[a][0] > yp[b][2]) return 0;
	if (yp[b][0] < xp[a][1] || yp[b][0] > xp[a][2]) return 0;
	return mat[xp[a][0]][yp[b][0]] == 'o';
}

void BuildGraph()
{
	int i, j;
	G = Empty;
	G.xn = xn;
	for (i = 1; i<=xn; ++i)
		for (j = 1; j<=yn; ++j)
			if (CheckCross(i, j))
				G.addedge(i, j+xn);
}

void memclr()
{
	clear(xp); clear(yp); clear(mat);
	xn = yn = 0;
}

int main()
{
	scanf("%d", &T);
	for (int ks = 1; ks<=T; ++ks)
	{
		scanf("%d%d", &n, &m);
		memclr();
		init();
		BuildGraph();
		printf("Case :%d\n%d\n", ks, G.Maxmatch());
	}
	return 0;
}


你可能感兴趣的:(ZOJ1654 place the robots(二分图匹配))