[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;
}