棋盘覆盖问题:在一个2^k×2^k(k≥0)个方格组成的棋盘中,恰有一个方格与其他方格不同,称该方格为特殊方格。显然,特殊方格在棋盘中可能出现的位置有4^k种,因而有4^k种不同的棋盘。棋盘覆盖问题要求用4种不同形状的L型骨牌覆盖给定棋盘上除特殊方格以外的所有方格,且任何2个L型骨牌不得重叠覆盖。如图:以4*4的棋盘为例:
四种不同形状的L型骨牌:
骨牌覆盖的结果:
棋盘填充的实现:
//分治回溯 分治的应用 之 棋盘覆盖问题
/*
利用分治算法 将棋盘分成三个子棋盘
首先要先判断特殊方格在哪个子棋盘中
若特殊方格在左上子棋盘中 就继续向下递归 将子棋盘再分为四个子棋盘即可
若左上子棋盘中没有特殊方格 我们就将左上子棋盘中的右下方的格子 当成一个特殊方格
再继续向下递归 将子棋盘再分为四个子棋盘 直到棋盘被全部覆为止
若右上子棋盘中没有特殊方格 我们就将右上子棋盘中的左下方的格子 当成一个特殊方格
再继续向下递归 将子棋盘再分为四个子棋盘 直到棋盘被全部覆为止
若左下子棋盘中没有特殊方格 我们就将下上子棋盘中的右上方的格子 当成一个特殊方格
再继续向下递归 将子棋盘再分为四个子棋盘 直到棋盘被全部覆为止
若右下子棋盘中没有特殊方格 我们就将右下子棋盘中的左上方的格子 当成一个特殊方格
再继续向下递归 将子棋盘再分为四个子棋盘 直到棋盘被全部覆为止
*/
public class ChessboardCoverage {
//表示棋盘尺寸
private static int BOARD_SIZE = 8;
//表示棋盘
private static int[][] chess = new int[BOARD_SIZE][BOARD_SIZE];
//骨牌编号 一层L型骨牌的编号要一直 0表示特殊方格
private static int title = 0;
public static void main(String[] args) {
Scanner input = new Scanner(System.in);
System.out.println("请输入特殊格子在棋盘中的坐标:");
int dr = input.nextInt(); //表示特殊格子在棋盘中的横坐标
int dc = input.nextInt(); //表示特殊格子在棋盘中的纵坐标
chessBoard(0, 0, dr, dc, BOARD_SIZE); //棋盘填充方法
for(int i = 0; i < chess.length; i++){ //遍历输出棋盘
for(int j = 0; j < chess.length; j++){
System.out.print(chess[i][j] + "\t");
}
System.out.println();
}
}
//棋盘填充方法
//(tr, tc)表示棋盘或者子棋盘的对应起点坐标 (dr, dc)表示棋盘中特殊坐标的位置 size表示棋盘或子棋盘尺寸
private static void chessBoard(int tr, int tc, int dr, int dc, int size) {
if(size == 1){ //递归临界条件 当棋盘尺寸等于1时 返回
return;
}
int s = size / 2; //表示棋盘或子棋盘尺寸 每次递归就除2 如将8*8的棋盘 分成四个4*4的子棋盘
int num = ++title; //更新L型骨牌编号 同一层的骨牌编号应该一致
//判断特殊坐标 在棋盘中的哪一部分子棋盘中
//如果特殊方格在左上子棋盘中
if(dr < tr + s && dc < tc + s){
chessBoard(tr, tc, dr, dc, s); //向下递归chessBoard方法 更新子方格起始位置和特殊方格位置
}else{ //如果特殊方格不在左上子棋盘中
chess[tr + s - 1][tc + s - 1] = num; //就规定左上角子棋盘中的右下角方格为特殊方格 将编号写入特殊方格
chessBoard(tr, tc, tr + s - 1, tc + s - 1, s);//向下递归chessBoard方法 更新子方格起始位置和特殊方格位置
}
//如果特殊方格在右上子棋盘
if(dr >= tr + s && dc < tc + s) {
chessBoard(tr + s, tc, dr, dc, s); //向下递归chessBoard方法 更新子方格起始位置和特殊方格位置
}else{ //如果特殊方格不在右上子棋盘中
chess[tr + s][tc + s - 1] = num; //就规定右上角子棋盘中的左下角方格为特殊方格 将编号写入特殊方格
chessBoard(tr + s, tc, tr + s,tc + s - 1, s); //向下递归chessBoard方法 更新子方格起始位置和特殊方格位置
}
//如果特殊方格在左下子棋盘
if(dr < tr + s && dc >= tc + s){
chessBoard(tr, tc + s, dr, dc, s); //向下递归chessBoard方法 更新子方格起始位置和特殊方格位置
}else{ //如果特殊方格不在左下子棋盘中
chess[tr + s - 1][tc + s] = num; //就规定左下角子棋盘中的右上角方格为特殊方格 将编号写入特殊方格
chessBoard(tr, tc + s, tr + s - 1, tc + s, s); //向下递归chessBoard方法 更新子方格起始位置和特殊方格位置
}
//如果特殊方格在右下子棋盘
if(dr >= tr + s && dc >=tc + s){
chessBoard(tr + s, tc + s, dr, dc, s); //向下递归chessBoard方法 更新子方格起始位置和特殊方格位置
}else{ //如果特殊方格不在右下子棋盘中
chess[tr + s][tc + s] = num; //就规定右下角子棋盘中的左上角方格为特殊方格 将编号写入特殊方格
chessBoard(tr + s, tc + s, tr + s, tc + s, s); //向下递归chessBoard方法 更新子方格起始位置和特殊方格位置
}
}
}
棋盘填充的结果为: