一、问题:对于一个 2^k * 2^k (k>=0) 的棋盘,恰有一个方格(下称为特殊方格)与其他不同,请用如下4种L型骨牌将除了特殊方格以外的格子覆盖,骨牌间不可重复覆盖
例题: 答案
---------------- ----------------
| | | | | | 1 | 1 | 2 | 2 |
+---+---+---+---+ +---+---+---+---+
| | X | | | | 1 | X | 3 | 2 |
+---+---+---+---+ +---+---+---+---+
| | | | | | 4 | 3 | 3 | 5 |
+---+---+---+---+ +---+---+---+---+
| | | | | | 4 | 4 | 5 | 5 |
+---+---+---+---+ +---+---+---+---+
X是特殊方格,1~5是骨牌编号。
编号可以随意排序
二、思路:
通过分析题目我们可以发现,由于用于覆盖格子的L型骨牌只能覆盖三格,
所以对于任意2*2的格子,总有一个无法被骨牌覆盖。对于这个4*4的格子来说无疑是特殊格子
但是对于题目来说呢?很明显,题目只有一个特殊的,无法被覆盖的格子啊,那这些所谓的特殊的格子是从哪里冒出来的呢?
很显然是属于别的骨牌的一部分嘛,你这个骨牌够不到的地方,不代表别的骨牌覆盖不了啊。
既然如此,我们将那些骨牌还原一下,让那些无法被覆盖的格子组成一个完整的骨牌好了。
于是我们得到下图(其中一种情况)。可以看到,有三个红色的格子组成一个完整的骨牌了:
嗯?绿色那块是怎么回事呢,怎么没有被拼成其他骨牌?
绿色那块对于格子G来说就是特殊格子嘛!
推而广之:绿色格子有没有可能是别的骨牌的一部分?很有可能:
我们可以这样一路向上分析(当然对于格子B来说不可能是其他骨牌的一部分了),可以推导出16*16,32*32的棋盘的情况。
这样,对于这个题目已经自底向上分析一波了
只要逆过来,自顶向下分析,就能得到本题的解法
刚才我们分析的时候是组成骨牌,反过来不就变成了拆散骨牌了嘛:
1、对于题目给出的棋盘G,平分为四块分棋盘。含特殊格子的分棋盘为G1(一个),不含特殊格子的为G2,G3,G4
2、用一个骨牌X覆盖棋盘,且被覆盖的格子X1,X2,X3分别在G2,G3,G4上
G1的特殊格子为题目的特殊格子;G2,G3,G4的特殊格子则为被骨牌X覆盖的X1,X2,X3
这样每个分棋盘都有特殊格子啦!
对于每个分棋盘G1,G2,G3,G4再次重复如上的分割方式,直到分割成2*2的小格子,分无可分为止。
对于分无可分的格子,我们给它盖上骨牌就行了。
当然,题目棋盘大小可能为1*1,到时候做些判断就行了
看!分治法在这道题目中的应用就是将一个大棋盘分割成4个都含有特殊格子的小棋盘(分),
等到分无可分时给棋盘盖上骨牌就行了(治)
代码:
#include<stdio.h>
#define maxn 4
int board[maxn][maxn];
int t;
void ChessBoard(int tr,int tc,int dr,int dc,int size){
int s,t1;
if(size==1)return;
t1=++t;
s=size/2;
if(dr<tr+s && dc<tc+s){
ChessBoard(tr,tc,dr,dc,s);
}else{
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{
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{
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{
board[tr+s][tc+s]=t1;
ChessBoard(tr+s,tc+s,tr+s,tc+s,s);
}
}
int main(){
t=0;
ChessBoard(0,0,3,2,4);
for(int i=0;i<maxn;++i){
for(int j=0;j<maxn;++j){
printf("%d ",board[i][j]);
}
printf("\n");
}
return 0;
}