问题:用4种不同形状的L型骨牌覆盖给定棋盘上除特殊方格以外的所有方格,且任何2个L型骨牌不得重叠覆盖。
思路:应用分治法
分治的技巧在于如何划分棋盘,使划分后的子棋盘的大小相同,并且每个子棋盘均包含一个特殊方格,从而将原问题分解为规模较小的棋盘覆盖问题。
k>0 时,可将2k×2k的棋盘划分为4个2(k-1)×2(k-1)的子棋盘,如图4.11(a)所示。这样划分后,由于原棋盘只有一个特殊方格,所 以,
这4个子棋盘中只有一个子棋盘包含该特殊方格,其余3个子棋盘中没有特殊方格。为了将这3个没有特殊方格的子棋盘转化为特殊棋盘,以便采用递归方法求 解,
可以用一个L型骨牌覆盖这3个较小棋盘的会合处,从而将原问题转化为4个较小规模的棋盘覆盖问题。递归地使用这种划分策略, 直至将棋盘分割为1×1的子棋盘。
package section2.Divide_and_Conquer;
import java.util.Scanner;
public class ChessboardCoverage {
public static void main(String[] args) {
int size = 4; // 棋盘的长,固定为4
int dr = 1; // 特殊棋子所在的行
int dc = 1; // 特殊棋子所在的列
ChessboardCoverage c = new ChessboardCoverage();
c.chessBoard(0, 0, dr, dc, size);
for (int i = 0; i < 4; i++) {
for (int j = 0; j < 4; j++) {
System.out.print(board[i][j] + " ");
}
System.out.println();
}
}
int title = 1; // 表示L型骨牌的编号
static int[][] board = new int[4][4];
// 处理带有特殊棋子的棋盘.tr、tc表示棋盘的入口即左上角的行列号,dr、dc表示特殊棋子的行列位置,size表示棋盘的行数或者列数
public void chessBoard(int tr, int tc, int dr, int dc, int size) {
if (size == 1) return;
int t = title++; // 骨牌编号
System.out.println(t);
int s = size / 2;// 每一次化大棋盘为一半的子棋盘
// 要处理带有特殊棋子的棋盘,第一步先处理左上棋盘(后面三步与此步重复)
if (dr < tr + s && dc < tc + s)// 左上角子棋盘有特殊棋子
chessBoard(tr, tc, dr, dc, s);// 处理有特殊棋子的左上角子棋盘
else// 处理无特殊棋子的左上角子棋盘
{
board[tr + s - 1][tc + s - 1] = t;// 设左上角子棋盘的右下角为特殊棋子,用t型的骨牌覆盖。由于骨牌有三种,当处理过程中同一级设置的特殊棋子用相同的骨牌覆盖
chessBoard(tr, tc, tr + s - 1, tc + s - 1, s);// 处理有用骨牌覆盖的格子作为特殊棋子的左上角子棋盘
}
// 第二步处理右上角棋盘
if (dr < tr + s && dc >= tc + s)// 右上角子棋盘有特殊棋子
{
chessBoard(tr, tc + s, dr, dc, s);// 处理有特殊棋子的右上角子棋盘
} else {
board[tr + s - 1][tc + s] = t;// 设右上角子棋盘的左下角为特殊棋子,用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;// 设左下角子棋盘的右上角为特殊棋子,用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;// 设子棋盘右下角的左上角为特殊棋子,用t型的骨牌覆盖。由于骨牌有三种,当处理过程中同一级设置的特殊棋子用相同的骨牌覆盖
chessBoard(tr + s, tc + s, tr + s, tc + s, s);// 处理有用骨牌覆盖的格子作为特殊棋子的右下角子棋盘
}
}
}