题意:有一个2^n*2^n的棋盘,在棋盘上面有一个特殊的方块,在此棋盘上面使用L型的骨牌进行覆盖,而且不能覆盖特殊的方块而且任意的骨牌也不能重叠,问应该怎么用L型的骨牌覆盖此棋盘?
棋盘:
这是一个棋盘,红色的为特殊的方格,我们要用如下的四种L型骨牌覆盖此棋盘:
L型骨牌:
思路:使用分治法对棋盘进行覆盖,首先把棋盘划分成四个部分,那么特殊的方格一定位于四个小的棋盘中的某一个。分别对四个小的棋盘进行覆盖,由于分治法处理的是划分成相同的情况,而特殊的方格只有一个且位于某一个小的棋盘中,我们需要把另外的三个棋盘都拿一个方格来作为特殊的方格,由此想出把拿出的三个格子组成一个L型骨牌,这样就满足了每个小的棋盘都一个
特殊的方格,而且拿出来的特殊方格形成一个L型的骨牌。然后对四个小的棋盘分而治之,直到方格数为1就停止!表明已经到达了最小的问题了。
a图是一个原始的棋盘,把大的棋盘划分成四个更小的棋盘,b图红色的代表原来的特殊的方格,而三个黄色的方格是没有特殊方格的棋盘拿出来的,在中间的位置刚好组成一个L型的骨牌。
代码:
#include <iostream>
#include<cmath>
#include<algorithm>
const int maxn = 500;
using namespace std;
int board[maxn][maxn],index = 0;//棋盘数组//指示L型棋盘的索引
//参数解析:
//tr(棋盘左上角方格的行号),tc(棋盘左上角方格的列号),dr(特殊方格的行号),dc(特殊方格的列号),size(棋盘大小)
void chessBoard(int tr,int tc,int dr,int dc,int size){
if(size == 1){//只有一个方格了,最小问题,直接返回
return;
}
int t = ++index,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,此方块为人为构造一个L型骨牌
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;
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;
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;
chessBoard(tr+s,tc+s,tr+s,tc+s,s);
}
}
void print(int n){
for(int i=0;i<n;i++){
for(int j=0;j<n;j++){
printf("%d%s",board[i][j],j==n-1?"\n":" ");
}
}
}
int main(int argc, char** argv) {
int n = 0,row,col;
printf("请输入棋盘大小n:(棋盘的规模为(2*n)*(2*n))\n");
scanf("%d",&n);
int size = (int)pow(2,n);
printf("请输入特殊的方格坐标:\n");
scanf("%d%d",&row,&col);//输入特殊方格的坐标
chessBoard(0,0,row,col,size);
print(size);//打印棋盘
return 0;
}