问题描述:在一个由*
(k
0)个方格组成的棋盘中,恰有一个方格与其他方格不同,称该方格为特殊方格。显然,特殊方格在棋盘中可能出现的位置有
种,因而有
种不同的棋盘。棋盘覆盖问题要求用四种不同形状的L形骨牌覆盖给定棋牌上除特殊方格以外的所有方格,且任何2个L形骨牌不得重叠覆盖.
想法:应用分治法求解棋盘覆盖问题的技巧在于如何划分棋盘,使划分后的子棋盘大小相同,并且每个子棋盘均包含一个特殊方格,从而将原问题分解为规模较小的棋盘覆盖问题。k>0时,可将*
的棋盘划分为4个
*
的子棋盘,这样划分之后,由于原棋盘只有一个特殊方格,这四个子棋盘中只有一个子棋盘包含特殊方格,其余三个子棋盘中没有特殊方格。为了将这三个没有特殊方格的子棋盘转化为特殊棋盘,以便采用递归方法求解,可以用一个L形骨牌覆盖三个较小棋盘的会合处,从而将原问题转化为4个较小规模的棋盘覆盖问题。递归的使用这种划分策略,直至将棋盘分割为1*1的子棋盘。
算法:(1)棋盘:可以使用一个二维数组board[size][size]表示一个棋盘,其中,size=。为了在地柜处理的过程中使用同一个棋盘,将board设为全局变量。
(2)子棋盘:整个棋盘用二维数组board[size][size]表示,其中的子棋盘由棋盘左下角的下标tr,tc和子棋盘大小s表示
(3)特殊方格;用board[dr][dc]表示特殊方格,dr和dc是该特殊方格在二维数组board中的下标。
算法实现如下
#include <iostream>
using namespace std;
#define N 4
int t = 0;
int board[N][N] = {0};
void ChessBoard(int tr, int tc, int dr, int dc, int size);
int main( )
{
int i, j, dr = 1, dc = 2;
ChessBoard(0, 0, dr, dc, N);
for (i = 0; i < N; i++)
{
for (j = 0; j < N; j++)
cout<<board[i][j]<<"\t";
cout<<endl;
}
return 0;
}
void ChessBoard(int tr, int tc, int dr, int dc, int size)
{
int s, t1;
if (size == 1) return; //只有一个特殊方格
t1 = ++t; // L型骨牌编号
s = size/2; // 划分棋盘
if (dr < tr + s && dc < tc + s) //特殊方格在左上角子棋盘中
ChessBoard(tr, tc, dr, dc, s); //递归处理子棋盘
else{ //用 t1号骨牌覆盖右下角,再递归处理子棋盘
board[tr + s - 1][tc + s - 1] = t1;
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 { //用 t1号骨牌覆盖左下角,再递归处理子棋盘
board[tr + s - 1][tc + s] = t1;
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 { //用 t1号骨牌覆盖右上角,再递归处理子棋盘
board[tr + s][tc + s - 1] = t1;
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 { //用 t1号骨牌覆盖左上角,再递归处理子棋盘
board[tr + s][tc + s] = t1;
ChessBoard(tr+s, tc+s, tr+s, tc+s, s);
}
}