题目描述
有许多大小为1×2的小卡片,有一个m×n棋盘,上面有k个洞。可以将卡片覆盖在棋盘上(卡片必须整个覆盖在棋盘上),正好覆盖一个1×2的空间,但是不能覆盖有洞的棋盘格子。任务是能否用一些卡片(不限个数),将棋盘的无洞格子全都覆盖?图显示了覆盖是否合法。
输入描述
有多组数据,每组数据第一行有三个整数m,n,k(0<m,n≤32 0≤k<m×n),随后k行,每行两个整数,表示洞的坐标。
输出描述
如果可以输出“YES”,否则输出“NO”。
分析
因为一张小卡片需要相邻两个格子组成,我们将整个棋盘将相邻的格子染上不同颜色,就像是国际象棋棋盘一样,如下图。在这样染色后,我们要保证每个白格和棕格一一匹配。
若删去格子数为奇数时,至少有一个格子没有匹配对象。
若删去格子数为偶数时,则若最大匹配数==剩余格子数/2时,覆盖合法,否则不合法
代码
#include<bits/stdc++.h>
using namespace std;
int vis[1001],d[1001][1001],st[50][50];
int p[1001];
int dir[4][2]= {0,1,1,0,-1,0,0,-1};
int N,M,n,m,k;
int u,v;
bool match(int e) {
for(int i=1; i<=N; i++) {
if(vis[i]||!d[e][i])
continue;
vis[i]=true;
if(p[i]==0||match(p[i])) {
p[i]=e;
return true;
}
}
return false;
}
int is_cnt() {
int cnt=0;
for(int i=1; i<=M; i++) {
memset(vis, false, sizeof vis);
if(match(i))
cnt++;
}
return cnt;
}
int main() {
cin>>n>>m>>k;
for(int i=1; i<=k; i++)
cin>>u>>v,st[u][v]=-1;//删去格子的标记
if(k&1) {//奇数一定不合法
cout<<"NO";
return 0;
}
bool f=0;
for(int i=1; i<=n; i++)
for(int j=1; j<=m; j++) {
if(st[i][j]==-1)
continue;
//对格子的染色分组
if(!f)
st[i][j]=++N;
else
st[i][j]=++M;
f=!f;
}
for(int i=1; i<=n; i++)
for(int j=1; j<=m; j++)
for(int k=0; k<4; k++) {
int dx=i+dir[k][0],dy=j+dir[k][1];
if(st[dx][dy]==-1)
continue;
d[st[i][j]][st[dx][dy]]=true;//在相邻格子间连一条边
}
if(n*m-k==is_cnt()*2)
cout<<"YES";
else
cout<<"NO";
return 0;
}
/*
解决方案: 873718
问题: 竞赛3162:E (5)
用户: 20222203362
判题类型: acm
提交时间: 2023-05-26 11:34:22
时间: 12MS
空间: 0.63MB
语言: C++20
代码长度: 1083B
判题时间: 2023-05-26 11:34:24
panjyash原创 禁止转载!!!
*/