给一个m*n的棋盘,然后挖掉p个格子,叫你用1*2的砖块来覆盖棋盘,问是否能完全覆盖。
好吧,,虽然知道是二分图,但是看到后在想线段树能不能做。。。。。原先有个贴小广告的线段树的题,不过忘了(QAQ捂脸)。
建图,首先,对于一个点来说,四个方向相邻的点都是可以匹配的。然后,用黑白点染色的方法把图分成两部分。嗯。
#include <stdio.h>
#include <string.h>
#define maxn 40
int vis[maxn*maxn],map[maxn*maxn][maxn*maxn],que[maxn*maxn],girl[maxn*maxn];
int n,m,p;
void add(int pos,int x)
{
int i=pos/n;
int j=pos%n;
if(!j&&(x==1)) return;
if(!j&&i==m&&(x==1||x==n)) return;
if(!j&&i==1&&x==-n) return;
if(!i&&j==1&&(x==-1||x==-n)) return;
if(j==1&&(x==-1)) return;
if(j==1&&(i==m-1)&&(x==-1||x==n)) return;
if(pos+x<1||pos+x>m*n) return;
if(que[pos+x]==-1) return;
map[pos][pos+x]=1;
// printf("map[%d][%d]=%d\n",pos,pos+x,map[pos][pos+x]);
}
void match()
{
int i,j,k;
for(i=0;i<m;i++)
{
for(j=i%2;j<n;j+=2)
{
int tmp=i*n+j+1;
if(que[tmp]==-1) continue;
add(tmp,1);add(tmp,-1);add(tmp,n);add(tmp,-n);
}
}
}
int find(int pos)
{
int i,j,k;
for(i=1;i<=m*n;i++)
{
if(map[pos][i]==1&&!vis[i])
{
vis[i]=1;
if(!girl[i]||find(girl[i]))
{
girl[i]=pos; //printf("girl[%d]=%d\n",i,pos);
return 1;
}
}
}
return 0;
}
int work()
{
int i,j,k;
for(i=0;i<p;i++)
{
scanf("%d%d",&j,&k);
que[(k-1)*n+j]=-1;
// printf("que[%d]=%d\n",(k-1)*n+j,que[(k-1)*n+j]);
}
match();
//print();
int ret=0;
for(i=0;i<m;i++)
{
for(j=i%2;j<n;j+=2)
{
k=i*n+j+1;
if(que[k]==-1) continue;
memset(vis,0,sizeof(vis));
if(!find(k)) return 0;
}
}
return 1;
}
void init()
{
memset(girl,0,sizeof(girl));
memset(map,0,sizeof(map));
memset(que,0,sizeof(que));
}
int main()
{
while(scanf("%d%d%d",&m,&n,&p)!=EOF)
{
int i,j,k;
init();
if(work()) printf("YES\n");
else printf("NO\n");
}
return 0;
}
/*
4 3 2
2 1
3 3
4 4 4
3 3
3 2
2 2
2 3
*/