ACM->uvalive->Sentry Robots(二分图匹配的最小点覆盖)

Sentry Robots
Time Limit:1000MS     Memory Limit:0KB     64bit IO Format:%lld & %llu

Description

Download as PDF

We need to guard a set of points of interest using sentry robots that can not move or turn. We can position a sentry at any position facing either north, south, east or west. Once a sentry is settled, it guards the points of interest that are infront of it. If two or more points are in the same row or column a single robot can guard them all. Unfortunately, there are also some obstacles that the robot cannot see through.

\epsfbox{p12549a.eps}

From a set of points of interest and obstacles lying on a grid, calculate the minimum number of robots needed to guard all the points. In order to guard a point of interest, a robot must be facing the direction of this point and must not be any obstacles in between.

Given the following grid, where # represents an obstacle and * a point of interest, the minimum number of robots needed is 2 (a possible position and orientation is shown using arrows for each robot). Note that this is not the actual input or output, just a figure.

\epsfbox{p12549b.eps}

For the following grid we need 4 robots because of the obstacles.

\epsfbox{p12549c.eps}

Input

The first line of the input has an integer C representing the number of test cases that follow. Before each test case there is an empty line.

For each case, the first line has 2 integers, Y and X, representing the height and width of the grid. The next line has an integer that indicates the number of points of interest P. The following P lines will have the positions py and px of the points of interest, one point per line. The next line has an integer that indicates the number of obstacles W. The following W lines will have the positions wy and wx of an obstacle, one per line.

Output

For each test case print the minimum number of robots needed to guard all the points of interest, one per line.


CONSTRAINTS:


1$ \le$C$ \le$50
1$ \le$YX$ \le$100
0$ \le$P$ \le$Y*X
0$ \le$W$ \le$Y*X
0$ \le$P + W$ \le$Y*X
1$ \le$pxwx$ \le$X
1$ \le$pywy$ \le$Y

Sample Input

2

4 6
4
2 2
2 4
4 2
4 4
3
2 3
3 3
4 3

4 5
6
1 2
1 3
2 4
2 2
3 3
4 3
2
2 3
3 2

Sample Output

2

4


#include <iostream>
#include <string>
#include <string.h>
#include <cstdio>

using namespace std;

#define MAXN 100 + 10
#define MAXNN 5000 + 10

int row, col, p, w, n, m;
int temp[MAXN][MAXN];
int c[MAXNN][MAXNN];
int x[MAXN][MAXN], y[MAXN][MAXN];
int match[MAXNN];
bool vis[MAXNN];

void init()
{
	memset(match, -1, sizeof(match));
}

void memxy()
{	
	n = m = 1;
	
	for (int i = 1; i <= row; i++)
	{
		for (int j = 1; j <= col;)
		{
			while (j <= col && temp[i][j] != -1)
			{
				x[i][j] = n;
				j++;
			}
			while (j <= col && temp[i][j] == -1)
			{
				j++;
			}
			n++;
		}	
	}
	
	for (int i = 1; i <= col; i++)
	{
		for (int j = 1; j <= row;)
		{
			while (j <= row && temp[j][i] != -1)
			{
				y[j][i] = m;
				j++;
			}
			while (j <= row && temp[j][i] == -1)
			{
				j++;
			}
			m++;
		}
	}
	
	memset(c, 0, sizeof(c));
	
	for (int i = 1; i <= row; i++)
	{
		for (int j = 1; j <= col; j++)
		{
			if (temp[i][j] == 1)
			{
				c[x[i][j]][y[i][j]] = 1;
			}
		}
	}
}

bool dfs(int u)
{
	for (int i = 1; i <= m; i++)
	{
		if (c[u][i] && !vis[i])
		{
			vis[i] = true;
			
			if (match[i] == -1 || dfs(match[i]))
			{
				match[i] = u;
				return true;
			}
		}
	}
	
	return false;
}

void solve()
{
	int ans = 0;
	
	for (int i = 1; i <= n; i++)
	{
		memset(vis, false, sizeof(vis));
		
		if (dfs(i))
		{
			ans++;
		}
	}
	
	cout << ans << endl;
}

void input()
{
    int t, x, y;

    scanf("%d", &t);

    while (t--)
    {
    	init();
    	
        scanf("%d %d", &row, &col);

		memset(temp, 0, sizeof(temp));
		
        scanf("%d", &p);

        for (int i = 1; i <= p; i++)
        {
            scanf("%d %d", &x, &y);
            temp[x][y] = 1;
        }

        scanf("%d", &w);

        for (int i = 1; i <= w; i++)
        {
            scanf("%d %d", &x, &y);
            temp[x][y] = -1;
        }
		
		memxy();
		
        solve();
    }
}

int main()
{
    input();
    return 0;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值