poj2446 Chessboard(图的建模+二部图匹配)
Time Limit: 2000MS Memory Limit: 65536K
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.
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
首先如何把这个问题建立模型,通过把棋盘黑白染色,发现相邻关系变成了二部图,本题相当于一个二部图匹配问题。这是数算实习课程学习二部图的作业,如果不知道本题和二部图有关的话,这个想法还是很巧妙很不好想的。
建完图后就是二部图匹配算法了,比较简单。
本题精巧之处在于第一眼看上去与二部图没什么关系,模型需要自己建立。
Problem: 2446 User: 1500012772
Memory: 172K Time: 47MS
Language: C++ Result: Accepted
#include<stdio.h>
#include<memory.h>
const int N=1100;
int h,w,n;
bool legal[N];
inline int color(int no)
{
int x=no%w;
int y=no/w;
return (x+y)%2;
}
inline int number(int x,int y)
{
return x+y*w;
}
bool visit[N];
int match[N];
inline int Min(int x,int y)
{
return x<y?x:y;
}
inline int Max(int x,int y)
{
return x>y?x:y;
}
bool find(int x)
{
int x1=x%w,y1=x/w,y;
for (int x2=Max(x1-1,0);x2<=Min(x1+1,w-1);x2++)
for (int y2=Max(y1-1,0);y2<=Min(y1+1,h-1);y2++)
{
y=number(x2,y2);
//printf("%d,%d\n",x,y);
if (legal[y]&&(color(y)==1))
{
if (!visit[y])
{
visit[y]=true;
if ((match[y]==-1)||find(match[y]))
{
match[y]=x;
return true;
}
}
}
}
return false;
}
int main()
{
int k,x,y,ans=0;
memset(legal,true,sizeof(legal));
memset(match,-1,sizeof(match));
scanf("%d%d%d",&h,&w,&k);
n=h*w;
if ((n-k)%2==1)
{
printf("NO\n");
return 0;
}
for (int i=1;i<=k;i++)
{
scanf("%d%d",&x,&y);
legal[number(x-1,y-1)]=false;
}
for (int i=0;i<n;i++)
if ((color(i)==0)&&legal[i])
{
memset(visit,false,sizeof(visit));
if (find(i))
ans++;
}
/*
for (int i=0;i<n;i++)
printf("%d ",match[i]);
*/
if (ans*2!=n-k)
printf("NO\n");
else
printf("YES\n");
return 0;
}