题目链接: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();
}
}