(1)当k>0时,将 2 k × 2 k 2^k×2^k 2k×2k棋盘分割为4个 2 k − 1 2^{k-1} 2k−1× 2 k − 1 2^{k-1} 2k−1小棋盘:
(2)特殊方格必位于4个小棋盘之一中,其余3个小棋盘中无特殊方格,为了将这3个无特殊方格的小棋盘转化为特殊棋盘,可以用一个L型骨牌覆盖这3个小棋盘的会合处:
(3)将原问题转化为4个较小规模的棋盘覆盖问题
(4)递归地使用这种分割,直至棋盘简化为1×1棋盘
分治算法思想:
我们把一个 2 k × 2 k 2^k×2^k 2k×2k有一个特殊方格的棋盘分成了4个都有一个特殊方格 2 k − 1 2^{k-1} 2k−1× 2 k − 1 2^{k-1} 2k−1小棋盘,然后递归分解,直至棋盘简化为1×1棋盘。
具体过程:
(1)Step1:将大棋盘分成四个小棋盘
(2)Step2:四个小棋盘中必定有3个没有特殊方格,我们可以用一个L型骨牌覆盖这3个小棋盘的会合处构造出特殊方格。
(3)Step3:现在我们将一个大问题分解成了四个小问题,都有特殊方格,重复Step1和Step2,直到棋盘简化为1×1棋盘
(4)最终结果:
(1)如果特殊方格在左上角小棋盘中,我们可以直接以左上角的特殊方格继续分解覆盖,特殊方格没有在左上角中,我们是不是需要覆盖左上角棋盘与其他小棋盘汇合处的方格,然后以这个方格作为特殊方格继续分解覆盖,左上角棋盘与其他小棋盘汇合处的方格就是左上角棋盘最右下角的方格。
(2)如果特殊方格在右上角小棋盘中,我们可以直接以右上角的特殊方格继续分解覆盖,特殊方格没有在右上角中,我们是不是需要覆盖右上角棋盘与其他小棋盘汇合处的方格,然后以这个方格作为特殊方格继续分解覆盖,右上角棋盘与其他小棋盘汇合处的方格就是右上角棋盘最左下角的方格。
(3)如果特殊方格在左下角小棋盘中,我们可以直接以左下角的特殊方格继续分解覆盖,特殊方格没有在左下角中,我们是不是需要覆盖左下角棋盘与其他小棋盘汇合处的方格,然后以这个方格作为特殊方格继续分解覆盖,左下角棋盘与其他小棋盘汇合处的方格就是左下角棋盘最右上角的方格。
(4)如果特殊方格在右下角小棋盘中,我们可以直接以右下角的特殊方格继续分解覆盖,特殊方格没有在右下角中,我们是不是需要覆盖右下角棋盘与其他小棋盘汇合处的方格,然后以这个方格作为特殊方格继续分解覆盖,右下角棋盘与其他小棋盘汇合处的方格就是右下角棋盘最左上角的方格。
结束条件是棋盘大小为1×1棋盘。
public class Demo {
public static int num = 0;
public static void main(String[] args) {
int[][] board = {{0,-1,0,0},{0,0,0,0},{0,0,0,0},{0,0,0,0}};
System.out.println("需要覆盖的棋盘:");
for (int[] ints : board) {
for (int anInt : ints) {
System.out.print(anInt+" ");
}
System.out.println();
}
chessBoard(board,0,0,0,1,4);
System.out.println("覆盖后的棋盘:");
for (int[] ints : board) {
for (int anInt : ints) {
System.out.print(anInt+" ");
}
System.out.println();
}
}
/**
*
* @param board 棋盘
* @param tr 棋盘的最左上角方格的 x坐标
* @param tc 棋盘的最左上角方格的 y坐标
* @param dr 特殊方格的 x坐标
* @param dc 特殊方格的 y坐标
* @param size 棋盘的大小
*/
public static void chessBoard(int[][] board,int tr, int tc, int dr, int dc, int size){
//棋盘大小为1 x 1 ==》结束
if (size == 1){
return;
}
//棋盘大小的一半:
int s = size/2;
//覆盖的号码:
int t = ++num;
//左上角的判断:
if (dr < tr+s && dc < tc+s){
chessBoard(board,tr, tc, dr, dc, s);
}else {
board[tr+s-1][tc+s-1] = t;
chessBoard(board,tr,tc,tr+s-1,tc+s-1,s);
}
//右上角
if (dr < tr+s && dc >= tc+s){
chessBoard(board,tr, tc+s, dr, dc, s);
}else {
board[tr+s-1][tc+s] = t;
chessBoard(board,tr,tc+s,tr+s-1,tc+s,s);
}
//左下角的判断:
if (dr >= tr+s && dc < tc+s){
chessBoard(board,tr+s, tc, dr, dc, s);
}else {
board[tr+s][tc+s-1] = t;
chessBoard(board,tr+s,tc,tr+s,tc+s-1,s);
}
//右下角
if (dr >= tr+s && dc >= tc+s){
chessBoard(board,tr+s, tc+s, dr, dc, s);
}else {
board[tr+s][tc+s] = t;
chessBoard(board,tr+s,tc+s,tr+s,tc+s,s);
}
}
}
输出:我们把特殊方格放在了(0,1)位置
需要覆盖的棋盘:
0 -1 0 0
0 0 0 0
0 0 0 0
0 0 0 0
覆盖后的棋盘:
2 -1 3 3
2 2 1 3
4 1 1 5
4 4 5 5
可以用分治法的主定律公式,每次分解成4个小规模的问题:
我们这里k = l o g 2 n log_{2}n log2n ,因为我们把n x n的棋盘看成 2 k × 2 k 2^k×2^k 2k×2k ,自然k = l o g 2 n log_{2}n log2n