思路:为了完整的用完(4^k - 1)/3 个L型骨牌,不妨采用四等分划分,对于没有特殊方格的区域构造一个L型骨牌,这样使得所有区域再放一下L型骨牌刚刚好把整个棋盘放满,然后再进行四等分递归划分,直到只有一个方格时才结束划分,应该算是一个经典的分治法吧。
代码:
#include<bits/stdc++.h>
using namespace std;
const int maxn = 1e4 + 10;
int chess[maxn][maxn];
int cnt = 1;
void dfs(int sr,int sc,int len,int dx,int dy){
if(len == 1)return; // 递归出口,即只有一个格子的时候
len /= 2; // 四等分划分即除二
cnt ++ ;//编号
if(dx < sr + len && dy < sc + len){ // 特殊方格在第一个区间
dfs(sr,sc,len,dx,dy); //无需放置L型骨牌,继续划分(len 已经改变)
}else{
chess[sr + len -1][sc + len -1] = cnt;//特殊方格不在第一个区间,即需要放置L型骨牌
dfs(sr,sc,len,sr+len-1,sc+len-1);//放置完了后,当前区域的L型骨牌已经变成当前区域的特殊方格,继续划分(注意区域左上角和特殊方格的坐标变化)
}
//下面的等价,不再赘述
if(dx < sr + len && dy >= sc + len){
dfs(sr,sc + len,len,dx,dy);
}else{
chess[sr + len - 1][sc + len] = cnt;
dfs(sr,sc + len,len,sr + len - 1,sc + len);
}
if(dx >= sr + len && dy < sc + len){
dfs(sr + len,sc,len,dx,dy);
}else{
chess[sr + len][sc + len - 1] = cnt;
dfs(sr + len,sc,len,sr + len,sc + len -1);
}
if(dx >= sr + len && dy >= sc + len){
dfs(sr + len , sc + len ,len,dx,dy);
}else{
chess[sr + len][sc + len] = cnt;
dfs(sr + len , sc + len , len ,sr + len, sc + len);
}
}
int main(){
srand(time(0));
int k;cin>>k;
int len = 1 << k;//2 ^ k
int r = rand()%len + 1;//2 ^ k * 2 ^ k 方格种随机省生成一个特殊方格
int c = rand()%len + 1;
chess[r][c] = 1;//标号
dfs(1,1,len,r,c);//递归划分
for(int i = 1; i <= len ; i++){
for(int j = 1 ; j <= len ; j++){
cout<<chess[i][j]<<" ";
}
cout<<endl;
}
}