Time Limit: 2000MS | Memory Limit: 65536K | |
Total Submissions: 21308 | Accepted: 6683 |
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.
题目大意就是给你一个n*m的矩形,有些点不能覆盖,能否用1*2的矩形将大矩形完全覆盖(除去不能覆盖的点)。
两个正方形组成一个矩形,则可以将问题转换成是否可以将大矩形相邻的两个空格一一匹配,除了不能覆盖的点,图上所有空格均被包含在二分图的最大匹配。
做法一是不分两个点集,建双向边,最后匹配是最大匹配两倍;做法二是i+j为奇数的点向偶数点建单向边,跑最大匹配。
注意坑点:x,y是y行x列的空格不能覆盖,而不是x行y列,我佛了。。。
另外我竟然因为把存匹配的数组写成bool型调了一个小时。。。
做法一
#include <cstdio>
#include <cstring>
#define mem(a,b) memset(a,b,sizeof(a))
using namespace std;
int map[40][40];
int line[1600][1600];
bool used[1600],vis[40][40];
int cnt,ans[1600];
bool found(int x)
{
for(int i=1;i<cnt;i++)
{
if(line[x][i]&&!used[i])
{
used[i]=1;
if(!ans[i]||found(ans[i]))
{
ans[i]=x;
return 1;
}
}
}
return 0;
}
int main()
{
int n,m,k;
while(~scanf("%d%d%d",&n,&m,&k))
{
mem(vis,0);
mem(line,0);
int x,y;
for(int i=0;i<k;i++)
{
scanf("%d%d",&x,&y);
vis[y][x]=1;
}
if((n*m-k)&1)
{
printf("NO\n");
continue;
}
cnt=1;
for(int i=0;i<=n;i++)
vis[i][0]=1;
for(int i=0;i<=m;i++)
vis[0][i]=1;
for(int i=1;i<=n;i++)
{
for(int j=1;j<=m;j++)
{
if(vis[i][j])
continue;
map[i][j]=cnt++;
if(!vis[i-1][j])
line[map[i-1][j]][map[i][j]]=line[map[i][j]][map[i-1][j]]=1;
if(!vis[i][j-1])
line[map[i][j-1]][map[i][j]]=line[map[i][j]][map[i][j-1]]=1;
}
}
mem(ans,0);
int res=0;
for(int i=1;i<cnt;i++)
{
mem(used,0);
if(found(i))
res++;
}
if(res+k==n*m)
printf("YES\n");
else
printf("NO\n");
}
}
做法二:
#include <cstdio>
#include <cstring>
#define mem(a,b) memset(a,b,sizeof(a))
using namespace std;
int map[50][50];
int line[2000][2000];
bool used[2000],vis[50][50];
int cnta,cntb,ans[2000];//竟然把ans定义到bool里了
bool found(int x)
{
for(int i=1;i<cntb;i++)
{
if(line[x][i]&&!used[i])
{
used[i]=1;
if(!ans[i]||found(ans[i]))
{
ans[i]=x;
return 1;
}
}
}
return 0;
}
int main()
{
int n,m,k;
while(~scanf("%d%d%d",&n,&m,&k))
{
mem(vis,1);
mem(line,0);
int x,y;
for(int i=0;i<k;i++)
{
scanf("%d%d",&x,&y);
vis[y][x]=0;
}
cnta=cntb=1;
for(int i=0;i<=n+1;i++)//四周都要封
vis[i][0]=vis[i][m+1]=0;
for(int i=0;i<=m+1;i++)
vis[0][i]=vis[n+1][i]=0;
for(int i=1;i<=n;i++)
{
for(int j=1;j<=m;j++)
{
if(!vis[i][j])
continue;
if(((i+j)&1)==1)
map[i][j]=cnta++;
else
map[i][j]=cntb++;
}
}
if(cnta!=cntb)
{
printf("NO\n");
continue;
}
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++)
{
if(((i+j)&1)==0||!vis[i][j])//&的优先级比==低,所以(i+j)&1==0永远是假!!!!(&,|,^。都比==低)
continue;
if(vis[i-1][j])
line[map[i][j]][map[i-1][j]]=1;
if(vis[i][j-1])
line[map[i][j]][map[i][j-1]]=1;
if(vis[i+1][j])
line[map[i][j]][map[i+1][j]]=1;
if(vis[i][j+1])
line[map[i][j]][map[i][j+1]]=1;
}
mem(ans,0);
int res=0;
for(int i=1;i<cnta;i++)
{
mem(used,0);
if(found(i))
res++;
}
if(res*2+k==n*m)
printf("YES\n");
else
printf("NO\n");
}
}