棋盘覆盖问题
棋盘覆盖问题
这是算法课上老师讲的一道分治题目,题目描述如下:
在一个2^k*2^k个方格组成的棋盘中,若恰有一个方格与其他方格不同,则称该方格为一个特殊方格。
下图的棋盘是k=2时4*4的棋盘方格
用四种不同的L型骨牌去覆盖除特殊方格外的所有方格,且任何2个L型骨牌不得重叠覆盖。
这里,我们容易得到用到的L型骨牌数量为(4^k-1)/3;
我们采用分治策略,将2^k*2^k的方格分成4个2^(k-1)*2^(k-1),如下图:
特殊方格必位于4个较小棋盘中,其余3个子棋盘中无特殊方格。
为了将这3个子棋盘转化为特殊棋盘,可以用一个L型骨牌覆盖这3个较小棋盘
的汇合处,这3个子棋盘被L型骨牌覆盖的方格就成为该棋盘上的特殊方格。递归地使用这种分割,直至棋盘简化成1*1。如下图所示:
对于棋盘结构设计如下:
1、棋盘:可以用一个二维数组board[size][size]表示一个棋盘,其中,size=2^k。为了在递归处理的过程中使用同一个棋盘,将数组board设为全局变量;
2、子棋盘:整个棋盘用二维数组board[size][size]表示,其中的子棋盘由棋盘左上角的下标tr、tc和棋盘大小s表示;
3、特殊方格:用board[dr][dc]表示特殊方格,dr和dc是该特殊方格在二维数组board中的下标;
4、L型骨牌:一个2^k×2^k的棋盘中有一个特殊方格,所以,用到L型骨牌的个数为(4^k-1)/3,将所有L型骨牌从1开始连续编号,用一个全局变量tile表示。
我们先分析一层递归的情况:
我们创建一个函数void ChessBoard(int tr,int tc,int dr,int dc,int size);
我们创建一个变量s=size/2,用来分割棋盘
左上子棋盘左上角坐标为(tr,tc)
右上子棋盘左上角坐标为(tr,tc+s)
左下子棋盘左上角坐标为(tr+s,tc)
右下子棋盘左上角坐标为(tr+s,tc+s)
我们L骨牌覆盖的中心区域坐标为:(tr+s-1,tc+s-1),(tr+s-1,tc+s),(tr+s,tc+s-1),(tr+s,tc+s);
这里我们以右上子棋盘递归为例,剩下的三个子棋盘只需要找到相应的坐标替换即可。
如果特殊方格在右上子棋盘中,只需要将方格左上角坐标替换为(tr,tc+s),
否则我们用一个变量t记下此时L型骨牌序号,并将对应的中心坐标用board[][]数组记下
这里我们选的是右上,所以board[tr+s-1][tr+s]=t;
这里我们这一层递归对应的L型骨牌的t是一样的,然后我们再递归这一情况。
注意:此时不仅子方格坐标已经改变,特殊方格坐标也已经改变。此时右上的特殊方格坐标更新为:(tr+s-1,tc+s)。
递归这个过程我们就完成了一个子方格的覆盖操作,然后再去覆盖其它3个子方格进行同样的操作,只需更改一下坐标即可。
附代码:
1 |
|
Input:
2
2 2
Output:
2 2 3 3
2 -1 1 3
4 1 1 5
4 4 5 5