poj 2446 Chessboard(二分图)

题意,在m*n的图中,把k个点除开后,看能否用1*2的木块把图完全覆盖,不能重叠,考虑到集合,把每对点当作匹配边,如果最大匹配是n*m-k,则YES

ChessboardTime Limit:2000MS    Memory Limit:65536KB    64bit IO Format:%lld & %llu

Description

Alice and Bob often play games on chessboard. One day, Alice draws a board with size M * N. She wants Bob to use a lot of cards with size 1 * 2 to cover the board. However, she thinks it too easy to bob, so she makes some holes on the board (as shown in the figure below).

We call a grid, which doesn’t contain a hole, a normal grid. Bob has to follow the rules below:
1. Any normal grid should be covered with exactly one card.
2. One card should cover exactly 2 normal adjacent grids.

Some examples are given in the figures below:

A VALID solution.


An invalid solution, because the hole of red color is covered with a card.


An invalid solution, because there exists a grid, which is not covered.

Your task is to help Bob to decide whether or not the chessboard can be covered according to the rules above.

Input

There are 3 integers in the first line: m, n, k (0 < m, n <= 32, 0 <= K < m * n), the number of rows, column and holes. In the next k lines, there is a pair of integers (x, y) in each line, which represents a hole in the y-th row, the x-th column.

Output

If the board can be covered, output "YES". Otherwise, output "NO".

Sample Input

4 3 2
2 1
3 3

Sample Output

YES
AC代码:

#include <iostream>
#include <stdio.h>
#include <algorithm>
#include <string.h>
#define maxn 35
#define maxn1 33*33
using namespace std;
int n, m, k;
int cnt;
int W[maxn1][maxn1];
int map[maxn][maxn];
int lef[maxn1];
bool T[maxn1];
bool vis[maxn][maxn];
bool match(int i)
{
	for (int j = 1; j <= cnt; j++)
	{
		if (W[i][j] && !T[j])
		{
			T[j] = true;
			if (lef[j] == 0 || match(lef[j]))
			{
				lef[j] = i;
				return true;
			}
		}
	}
	return false;
}
void KM()
{
	int sum = 0;
	for (int i = 1; i <= cnt; i++)
	{
		memset(T, 0, sizeof(T));
		if (match(i))
		{
			sum++;
		}
	}
	if (sum == m*n-k)
		printf("YES\n");
	else
		printf("NO\n");
}
int main()
{
	while (scanf("%d%d%d", &m, &n, &k) != EOF)
	{
		memset(W, 0, sizeof(W));
		memset(lef, 0, sizeof(lef));
		memset(vis, 0, sizeof(vis));
		int a, b;
		for (int j = 1; j <= k; j++)
		{
			scanf("%d%d", &a, &b);
			vis[b][a] = 1;
		}
		cnt = 1;
		for (int i = 1; i <= m; i++)
			for (int j = 1; j <= n; j++)
			{
				if (!vis[i][j])//把每个点标记,就能存进M[][]
					map[i][j] = cnt++;
			}
		cnt--;
		if ((cnt - k) & 1)
			printf("NO\n");
		else
		{
			for (int i = 1; i <= m; i++)
				for (int j = 1; j <= n; j++)
				{
					if (!vis[i][j])
					{
						//四个方向
						if (i > 1 && !vis[i - 1][j])
							W[map[i][j]][map[i - 1][j]] = 1;
						if (i < m&&!vis[i + 1][j])
							W[map[i][j]][map[i + 1][j]] = 1;
						if (j > 1 && !vis[i][j - 1])
							W[map[i][j]][map[i][j - 1]] = 1;
						if (j < n&&!vis[i][j + 1])
							W[map[i][j]][map[i][j + 1]] = 1;
					}
				}
			KM();
		}
	}
	return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值