一、引子
最近又重新上了算法课,现在想来有点汗颜,大学期间已经学习了一个学期,到现在却依然感觉只是把老师讲过的题目弄懂了,并没有学到算法的一些好的分析方法和思路,碰到一个新的问题后往往感觉很棘手,痛定思痛之后觉得还是好好再学习一遍,争取能理解透彻每种算法的思路和核心,同时也劝诫各位同行们做事要脚踏实地,不能应付老师的作业,最后吃亏的还是自己啊。
二、棋盘覆盖问题
为一特殊棋盘。现有四种L型骨牌如下图所示,要用这四种骨牌覆盖棋盘上除特殊方格之外的其他所有格子,且两个L型骨牌不能相互覆盖。
三、解题思路
假设特殊格子出现在(0,2)这个位置,如图3所示,那么对于含有特殊格子的右上角的子棋盘我们用0型骨牌填充,如图4。那么剩余的三个子棋盘呢,这个时候我们发现左上角只能覆盖3型和2型,其他两种会有剩余空格,如果覆盖2型骨牌,后面的左下角必然无法完全覆盖(自己可以试一下),则只能使用3型骨牌覆盖,以此类推,我们也可以覆盖左下角和右下角此时只剩三个格子没有覆盖,如图5所示。现在仔细观测剩余的三个格子,我们发现他们都是分开在三个子棋盘里,那么这些空格子在子棋盘中是无法直接被覆盖的,因为每个子棋盘只剩一个空格子了,我们是不是可以把这个空格子当成一个特殊格子,这样四个子棋盘都是含有一个特殊格子的小棋盘,这样原问题就变成了四个同样的子问题,再求解了每个子棋盘后,我们再对三个假的子棋盘格子进行覆盖(如图6)。
那么如何选择空格作为子棋盘的特殊格子呢,通过观察我们发现,对于含有特殊格子的子棋我们不用指定特殊格子,对于剩下三个子棋盘,我们指定四个子棋盘的交界处的格子作为特殊格子。
四、归纳
五、代码实现
#include <iostream>
#include<memory.h>
using namespace std;
int **chessBoard;
int k=1;
int length=0;
int blueRow=-1;
int blueCol=-1;
void init();
void fillBoard(int **_chessBoard,int r,int c,int type);
void fillChessBoard(int **_chessBoard,int k,int blue_row,int blue_col,int baseRow,int baseCol);
void output(int **_chessBoard);
int main()
{
init();
fillChessBoard(chessBoard,k,blueRow,blueCol,0,0);
output(chessBoard);
for(int i=0;i<length;i++)
{
delete [] chessBoard[i];
}
delete chessBoard;
return 0;
}
void init()
{
cout<<"please input number k:"<<endl;
cin>>k;
cout<<"please input blue grid coordinate:row column"<<endl;
cin>>blueRow>>blueCol;
length=(1<<k);//长和宽均为2^k
//动态分配2^k数组
chessBoard=new int*[length];
for(int i=0;i<length;i++)
{
chessBoard[i]=new int[length];
//初始化为-1
memset(chessBoard[i],-1,length*sizeof(int));
}
chessBoard[blueRow][blueCol]=4;
}
void output(int **_chessBoard)
{
for(int i=0;i<length;i++)
{
for(int j=0;j<length;j++)
{
cout<<" "<<_chessBoard[i][j];
}
cout<<endl;
}
cout<<endl;
}
void fillBoard(int **_chessBoard,int r,int c,int type)
{
for(int i=0;i<2;i++)
{
for(int j=0;j<2;j++)
{
if((i*2+j)!=type)
{
if(_chessBoard[r+i][c+j]!=-1)
cout<<"error"<<endl;
_chessBoard[r+i][c+j]=type;
}
}
}
}
void fillChessBoard(int **_chessBoard,int level,int blue_row,int blue_col,int baseRow,int baseCol)
{
if(level==1)
{
int type=(blue_row<<1)+blue_col;
fillBoard (_chessBoard,baseRow,baseCol,type);
}else
{
//否则进行四等分,中间连接处自行填充
//新的四分格的宽度
int new_length=1<<(level-1);
int type=(blue_row/new_length)*2+blue_col/new_length;
for(int r=0;r<2;r++)
{
for(int c=0;c<2;c++)
{
if((r*2+c)==type)
{
fillChessBoard (_chessBoard,level-1,blue_row-r*new_length,blue_col-c*new_length,r*new_length+baseRow,c*new_length+baseCol);
}
else
{
fillChessBoard (_chessBoard,level-1,(new_length-1)*(1-r),(new_length-1)*(1-c),r*new_length+baseRow,c*new_length+baseCol);
}
}
}
fillBoard (_chessBoard,baseRow+new_length-1,baseCol+new_length-1,type);
}
}