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