POJ 2446 Chessboard二分图匹配

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

Hint


A possible solution for the sample input.


大意:一个棋盘,有k个点被标记特殊点,现在要求用1*2的小纸条覆盖整个棋盘,除特殊点外,且一个点不能被多个纸条覆盖到。问是否能办到。棋盘大小m*n(m,n<32,k<m*n)
分析:刚看这道题绞尽脑汁,因为是棋盘覆盖的题所以总以为会是分治或者是搜索什么的,结果联系了下最近学的二分图,发现了这么个情况:纸条大小1*2,也就是每个纸条只能覆盖相邻的两个点,而每个点最多被覆盖一次。意思是说每个点能跟哪几个点共用一个纸条(即匹配)是确定的,这样的话二分图的模型就出来了。
     怎么二分呢?我们把棋盘按照国际象棋的棋盘那样“涂色”,也就是一个黑点必匹配一个白点。我们给没个黑白点编号,且每个点和周围的最多四个点建一条边,这样二分图的模型就构造好了。最多有m*n/2个黑或白点,匈牙利算法不会超时。
    做匈牙利算法算出最大匹配ans,判断ans*2是否==m*n-k,如果等,说明每个点都被覆盖了,可解。不等,则不存在解。
代码如下:
#include<iostream>
#include<cstring>
#include<algorithm>
#include<cstdio>
#include<string>
#define MAXN 34
using namespace std;
int N,K,M,match[MAXN*MAXN],nb,nw,ans;
bool map[MAXN*MAXN][MAXN*MAXN],use[MAXN*MAXN];
int id[MAXN][MAXN],co[MAXN][MAXN];
int dx[4]={0,0,1,-1};
int dy[4]={1,-1,0,0};
bool DFS(int u)
{
	for(int i=1;i<=nw;i++)
		if(!use[i]&&map[u][i])
		{
			use[i]=1;
			if(match[i]==-1||DFS(match[i]))
			{
				match[i]=u;
				return 1;
			}
		}
	return 0;
}
int main()
{
	while(scanf("%d%d%d",&M,&N,&K)!=EOF)
	{
		memset(co,-1,sizeof(co));
		memset(map,0,sizeof(map));
		memset(id,0,sizeof(id));
		memset(match,-1,sizeof(match));
		nb=nw=ans=0;
		for(int i=1;i<=K;i++)
		{
			int xx,yy;
			scanf("%d%d",&xx,&yy);
			co[xx][yy]=0;
		}
		for(int i=1;i<=N;i++)
			for(int j=1;j<=M;j++)
			{
				if(co[i][j]==0) continue;
				if((i%2==1&&j%2==1)||(i%2==0&&j%2==0))
				{
					co[i][j]=1;//black
					id[i][j]=++nb;
				}
				else
				{
					co[i][j]=2;//white
					id[i][j]=++nw;
				}
			}
		for(int i=1;i<=N;i++)
			for(int j=1;j<=M;j++)
			{
				if(co[i][j]==0) continue;
				for(int k=0;k<4;k++)
				{
					int tx=i+dx[k],ty=j+dy[k];
					if(tx>=1&&tx<=N&&ty>=1&&ty<=M&&co[tx][ty]!=0)
					{
						if(co[i][j]==1) map[id[i][j]][id[tx][ty]]=1;
						if(co[i][j]==2) map[id[tx][ty]][id[i][j]]=1;
					}
				}
			}
		for(int i=1;i<=nb;i++)
		{
			memset(use,0,sizeof(use));
			if(DFS(i)) ans++;
		}
		if(ans*2==M*N-K) printf("YES\n");
		else printf("NO\n");
	}
	return 0;
}


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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值