解题思路:这一题使用递归的解法比较便于理解,这里可以采用前面使用过的分治算法,将整个棋盘分成四个部分。直接划分后只有一个部分会有黑色图块,而其余三个部分则都是白色图块。这里可以采取人为添加的方式。在其余三个部分增加一个骨牌覆盖到三个部分,这样每个区块又都会包含黑色图块,然后分部分继续求解。递归的返回条件则是划分的图块只有一块时,直接返回即可。注意学习题目的递归思想。
题目大意:
棋盘覆盖问题要求在2^k * 2^k 个方格组成的棋盘中,你给定任意一个特殊点,用一种方案实现对除该特殊点的棋盘实现全覆盖。
建立模型如图:
解决方案就是利用分治法,将方形棋盘分成4部分,如果该特殊点在某一部分,我们就去递归他,如果不在某一部分,我们假设一个点为特殊点,同样递归下去,知道全覆盖。
左上角的子棋盘(若不存在特殊方格):则将该子棋盘右下角的那个方格假设为特殊方格;
右上角的子棋盘(若不存在特殊方格):则将该子棋盘左下角的那个方格假设为特殊方格;
左下角的子棋盘(若不存在特殊方格):则将该子棋盘右上角的那个方格假设为特殊方格;
右下角的子棋盘(若不存在特殊方格):则将该子棋盘左上角的那个方格假设为特殊方格;
#include<cstdio>
#include<cstring>
#include<iostream>
using namespace std;
int ch[1000][1000];
void divide(int sx,int sy,int row,int X,int Y)
{
if(row==1) return;
int midx=sx+row/2,midy=sy+row/2;
if(X<midx&&Y<midy) //判断现有图块在哪个位置
{
ch[midx][midy]=ch[midx-1][midy]=ch[midx][midy-1]=2; //将其他无黑色图块的部分也覆盖了
divide(sx,sy,row/2,X,Y); //继续递归求解各部分
divide(sx,midy,row/2,midx-1,midy);
divide(midx,sy,row/2,midx,midy-1);
divide(midx,midy,row/2,midx,midy);
}
else if(X<midx&&Y>=midy)
{
ch[midx][midy]=ch[midx][midy-1]=ch[midx-1][midy-1]=1;
divide(sx,sy,row/2,midx-1,midy-1);
divide(sx,midy,row/2,X,Y);
divide(midx,sy,row/2,midx,midy-1);
divide(midx,midy,row/2,midx,midy);
}
else if(X>=midx&&Y<midy)
{
ch[midx][midy]=ch[midx-1][midy]=ch[midx-1][midy-1]=4;
divide(sx,sy,row/2,midx-1,midy-1);
divide(sx,midy,row/2,midx-1,midy);
divide(midx,sy,row/2,X,Y);
divide(midx,midy,row/2,midx,midy);
}
else if(X>=midx&&Y>=midy)
{
ch[midx][midy-1]=ch[midx-1][midy]=ch[midx-1][midy-1]=3;
divide(sx,sy,row/2,midx-1,midy-1);
divide(sx,midy,row/2,midx-1,midy);
divide(midx,sy,row/2,midx,midy-1);
divide(midx,midy,row/2,X,Y);
}
}
int main()
{
int k,x,y;
while(cin>>k>>x>>y)
{
x++;y++;ch[x][y]=0;
int row=1;
while(k--) row*=2;
divide(1,1,row,x,y);
for(int i=1;i<=row;i++)
{
for(int j=1;j<=row;j++)
{
cout<<ch[i][j]<<" ";
}
cout<<endl;
}
cout<<endl;
}
return 0;
}