题目链接:http://poj.org/problem?id=2446
题意:有一个n*m的棋盘,上面有k个洞,问你能不能用1*2,如果能就输出YES,否则输出NO
解析:如果把一个1*2的砖块能铺上去,看成一个格子和他相邻格子是有条边的,那么就可以把这个棋盘构成一个二分图,那么你只需要判断最大匹配是否等于空格数就可以了,注意:题目是先输入y再输入x
#include <iostream>
#include <algorithm>
#include <cstdio>
#include <cstring>
using namespace std;
const int maxn = 3005;
int a[maxn][maxn];
int g[maxn][maxn];
int dx[] = {0,1,-1,0};
int dy[] = {1,0,0,-1};
int match[maxn],vis[maxn];
void build(int x,int y,int n,int m)
{
for(int i=0;i<4;i++)
{
int tx = x+dx[i];
int ty = y+dy[i];
if(tx<1 || tx>n || ty<1 || ty>m)
continue;
if(a[tx][ty]!=-1)
g[a[x][y]][a[tx][ty]] = 1;
}
}
bool dfs(int u,int n)
{
for(int i=0;i<n;i++)
{
if(vis[i] || !g[u][i])
continue;
vis[i] = 1;
if(match[i]==-1 || dfs(match[i],n))
{
match[i] = u;
return 1;
}
}
return 0;
}
int main(void)
{
int n,m,k,x,y;
scanf("%d %d %d",&n,&m,&k);
for(int i=0;i<k;i++)
{
scanf("%d %d",&y,&x); //很关键
a[x][y] = -1;
}
int cnt = 0;
for(int i=1;i<=n;i++)
{
for(int j=1;j<=m;j++)
{
if(a[i][j]!=-1)
a[i][j] = cnt++;
}
}
if(cnt%2 || cnt==0)
puts("NO");
else
{
for(int i=1;i<=n;i++)
{
for(int j=1;j<=m;j++)
{
if(a[i][j]!=-1)
build(i,j,n,m);
}
}
int ans = 0;
memset(match,-1,sizeof(match));
// for(int i=1;i<=n;i++)
// {
// for(int j=1;j<=m;j++)
// printf("%d ",a[i][j]);
// puts("");
// }
// for(int i=0;i<cnt;i++)
// {
// for(int j=0;j<cnt;j++)
// printf("%d ",g[i][j]);
// puts("");
// }
for(int i=0;i<cnt;i++)
{
memset(vis,0,sizeof(vis));
if(dfs(i,cnt))
ans++;
}
if(ans==cnt)
puts("YES");
else
puts("NO");
}
return 0;
}