[POJ 2446]Chessboard
很容易看出是二分图最大匹配,可是怎么建图呢……
我们可以考虑把一个点的横纵坐标相加,和为偶数者称之为偶数点,反之为奇数点。我们发现,每个骨牌都正好覆盖了一个奇数点和一个偶数点。于是乎就能把点分为两个集合了,建图就很方便了。
代码:
#include <cstdio>
#include <cstring>
const int maxn=35,maxm=520;
bool G[maxm][maxm];
// Hungray
int odd_cnt=0,even_cnt=0;
bool vis[maxm];
int GirlFriend[maxm];
bool DFS(int x){
int i;
for(i=1;i<=even_cnt;i++)
if(G[x][i] && !vis[i]){
vis[i]=true;
if(!GirlFriend[i] || DFS(GirlFriend[i])){
GirlFriend[i]=x;
return true;
}
}
return false;
}
inline int Hungray(){
register int i,ans=0;
for(i=1;i<=odd_cnt;i++){
memset(vis,0,sizeof(vis));
if(DFS(i))
ans++;
}
return ans;
}
int n,m;
bool isHole[maxn][maxn];
int ct[maxn][maxn];
inline int AddPoint(int a,int b,int x,int y){
if(ct[x][y])
if(!isHole[x][y])
G[ct[a][b]][ct[x][y]]=true;
}
int main(){
int k,x,y;
register int i,j,tot;
scanf("%d%d%d",&m,&n,&k);
tot=m*n-k;
if(1&tot){
puts("NO");
return 0;
}
for(i=1;i<=k;i++){
scanf("%d%d",&x,&y);
isHole[y][x]=true;
}
for(i=1;i<=m;i++)
for(j=1;j<=n;j++){
if(isHole[i][j])
continue;
if(1&(i+j)){
ct[i][j]=++odd_cnt;
}else{
ct[i][j]=++even_cnt;
}
}
for(i=1;i<=m;i++)
for(j=1;j<=n;j++){
if(!isHole[i][j] && 1&(i+j)){
AddPoint(i,j,i-1,j);
AddPoint(i,j,i+1,j);
AddPoint(i,j,i,j-1);
AddPoint(i,j,i,j+1);
}
}
if(Hungray()==(tot/2)){
puts("YES");
}else{
puts("NO");
}
return 0;
}