题目链接:http://cstest.scu.edu.cn/soj/problem.action?id=2035
题意:一个n*m的表格,有一些格子是黑色的,问能否用一些1*2的骨牌把所有黑色的格子全部盖住,骨牌不能重叠。。
算法:
裸的二分匹配。。。
先把格子交替分成A、B两类点,使得只有A类点和B类点才能相邻。。
然后如果两个相邻的格子均为黑色就在它们之间建一条边。
最后用匈牙利算法求最大匹配,判断最大匹配数是否等于黑格子数的一半。
#include <cstdio> #include<cstring> #include<cmath> using namespace std; int n,m,cot,xm[4000],ym[4000],b[70][70],dx[4]= {-1,1,0,0},dy[4]= {0,0,1,-1}; bool a[70][70],cap[4000][4000],vis[4000]; bool findpath(int u) { int v; for(int i=0; i<4; i++) { if((u/m+dx[i])<0||(u/m+dx[i])==n||(u%m+dy[i])<0||(u%m+dy[i])==n)continue; v=(u/m+dx[i])*m+(u%m+dy[i]); if(vis[v]||a[u/m+dx[i]][u%m+dy[i]]==0)continue; vis[v]=true; if(ym[v]==-1||findpath(ym[v])) { ym[v]=u; xm[u]=v; return true; } } return false; } void dfs() { int ans=0; memset(ym,-1,sizeof(ym)); memset(xm,-1,sizeof(xm)); for(int i=0; i<n; i++) for(int j=0; j<m; j++) { if(!a[i][j])continue; if((i^j)&1)continue; if(xm[i*m+j]==-1) { memset(vis,0,sizeof(vis)); if(findpath(i*m+j)) { ans++; } } } if(ans*2==cot)puts("POSSIBLE\n"); else puts("IMPOSSIBLE\n"); } int main() { int i,j; char s[100]; while(scanf("%d%d",&n,&m)==2&&(n||m)) { getchar(); cot=0; memset(cap,0,sizeof(cap)); for(i=0; i<n; i++) { gets(s); for(j=0; j<m; j++) { if((s[j])=='#') { a[i][j]=1; cot++; } else a[i][j]=0; } } if(cot%2) { puts("IMPOSSIBLE\n"); continue; } dfs(); } }