简单描述:一个棋盘,有$2^k$×$2^k$个方格,其中有一个特殊方格,我想用4种L型骨牌覆盖这个棋盘。
先用数学归纳法:
(1)k=1时,有2×2个方格,其中有一个特殊方格,直接放一个L型骨牌就行——问题解决。
(2)k=2时,有4×4个方格,其中有一个特殊方格,自己画图想想,也可以解决。
(3)k=k时,也能分析。
以一个4×4的方格为例,board[1][1]代表特殊方格。
首先定义一下变量,tr表示棋盘左上角方格的行号,tc表示棋盘左上角方格的列号,dr表示特殊方格的行号,dc表示特殊方格的列号,size表示棋盘的边,tile=0先置为零,表示L型骨牌的编号
/ /// | |||
代码如下:
int [][]board=new int[100][100];
public void ChessBoard(int tr,int tc,int dr,int dc,int size){
int tile =0;
int t=tile++;
int s=size/2;
if(size==1){
return;
}
//第二象限
if(dr<tr+s &&dc<tc+s){切一刀,分成四个象限,看(tr,tc),所代表的定义,永远是左上角的点
第一象限如果没有特殊方格,把左下角置为特殊
第二象限如果没有特殊方格,把右下角置为特殊
第四象限如果没有特殊方格,把右上角置为特殊,同理。
ChessBoard(tr, tc, dr, dc, s);
}else {
board[tr+s-1][tc+s-1]=t;
ChessBoard(tr, tc, tr+s-1, tc+s-1, s);
//(tr,tc)一直都是定义在左上角的点,递归的时候也是,不过表示的话,以第一象限为例
意义上第一象限的左上角是(tr,tc),但是用(tr,tc+s)表示
}
//第一象限
if(dr<tr+s && dc>=tc+s){
ChessBoard(tr,tc+s,dr,dc,s);
}else{
board[tr+s-1][tc+s]=t;
ChessBoard(tr,tc+s,tr+s-1,tc+s,s);
}
第三象限(右下角)
if(dr>=tr+s && dc<tc+s){
ChessBoard(tr+s,tc,dr,dc,s)
}else{
board[tr+s][tc+s-1]=t;
ChessBoard(tr+s,tc,tr+s,tc+s-1,s);
}
if(dr>=tr+s && dc>=tc+s){
ChessBoard(tr+s,tc+s,dr,dc,s);
}
else{
board[tr+s][tc+s]=t;
ChessBoard(tr+s,tc+s,tr+s,tc+s,s);
}
以上是算法的实现,以下是我在学习过程中的一些理解:
(1)先用二分法:int s=size/2,对棋盘进行二分,二分十字交叉的位置,把一个棋盘(一次递归过程)分成了四个象限,可以在四个象限中操作。
(2)每个方格上方的坐标点,代表这个方格。
(3)重点:理解tr,tc的意思,是每个划分区域的左上方,递归之后也是如此,但是需要用整个棋盘的左上方(tr,tc)表示。
(4)if条件中dr与tr+s作比较,用来确定(dr,dc)的位置,从而确定划分特殊方格在每一个象限中的位置。
(5)调用函数进行递归,每个参数要传正确了。