Description
给定一个m×n的棋盘,上面有k个洞,求是否能在不重复覆盖且不覆盖到洞的情况下,用2×1的卡片完全覆盖棋盘。
Input
第一行有三个整数n,m,k(0<m,n<=32, 0<=k<m×n),m表示行数,n表示列数。
接下来k行,每行两个整数y,x,表示(x,y)上有个洞。
Output
如果能覆盖,输出YES;否则输出NO。
Sample Input
4 3 2
2 1
3 3
Sample Output
YES
Solution
32×32的范围如果暴搜剪枝能力比较强的人也许能过吧,但是我并没有那个能力。
2×1的卡片去覆盖的话,就是两个相邻的格子为一对,且每个格子只能属于一对(有洞的格子不属于任何一对)。
怎么有点像二分图匹配?那就想想怎么构图吧。
定义两格子相邻当且仅当它们有一条公共边时。
那么两个相邻的格子就得在不同集合里,按这样分正好能分成两个集合。
然后两个可放卡片的相邻格子连一条边,这样二分图就构成功了。
1 #include<set> 2 #include<cmath> 3 #include<ctime> 4 #include<queue> 5 #include<stack> 6 #include<cstdio> 7 #include<vector> 8 #include<cstring> 9 #include<cstdlib> 10 #include<iostream> 11 #include<algorithm> 12 #define D 5 13 #define N 35 14 #define K 513 15 #define M 2049 16 using namespace std; 17 struct graph{ 18 int nxt,to; 19 }e[M]; 20 int x[D]={0,0,0,1,-1},y[D]={0,1,-1,0,0}; 21 int g[K],fr[N*N],m,n,k,cnt,tot,sum; 22 bool b[N][N],u[N*N]; 23 inline void addedge(int x,int y){ 24 e[++cnt].nxt=g[x];g[x]=cnt;e[cnt].to=y; 25 } 26 inline bool match(int k){ 27 for(int i=g[k];i;i=e[i].nxt) 28 if(!u[e[i].to]){ 29 u[e[i].to]=true; 30 if(!fr[e[i].to]||match(fr[e[i].to])){ 31 fr[e[i].to]=k;return true; 32 } 33 } 34 return false; 35 } 36 inline bool hungary(){ 37 for(int i=1;i<=tot;i++){ 38 memset(u,0,sizeof(u)); 39 if(!match(i)) return false; 40 } 41 return true; 42 } 43 inline void init(){ 44 scanf("%d%d%d",&m,&n,&k); 45 for(int i=1;i<=m;i++) 46 for(int j=1;j<=n;j++) 47 b[i][j]=true; 48 for(int i=1,j,l;i<=k;i++){ 49 scanf("%d%d",&j,&l); 50 b[l][j]=false; 51 } 52 for(int i=1;i<=m;i++) 53 for(int j=!(i&1)+1;j<=n;j+=2) 54 if(b[i][j]){ 55 ++tot; 56 for(int l=1;l<D;l++) 57 if(b[i+x[l]][j+y[l]]) 58 addedge(tot,(i+x[l]-1)*n+j+y[l]); 59 } 60 for(int i=1;i<=m;i++) 61 for(int j=(i&1)+1;j<=n;j+=2) 62 if(b[i][j]) sum++; 63 if(sum==tot&&hungary()) printf("YES "); 64 else printf("NO "); 65 } 66 int main(){ 67 freopen("chessboard.in","r",stdin); 68 freopen("chessboard.out","w",stdout); 69 init(); 70 fclose(stdin); 71 fclose(stdout); 72 return 0; 73 }