其实就是算法设计课上的例题,然后我找到OJ上的题测试一下。
传送门: 洛谷 U91193 棋盘覆盖
细节挺多的,我主要卡的地方就是计数。计数的时候注意要先用一个变量存骨牌编号,因为之后再递归编号就增加了,而实际上返回本层的时候应该填入的是原来的编号。
还有就是题面有点问题,矩阵得开到1000*1000,否则RE。
总体就是分治的思想,具体实现见代码注释。
#include <bits/stdc++.h>
using namespace std;
const int N=1e3+10;
int k,n,bx,by,tot,ans[N][N];
// L形骨牌编号tot
void solve(int x1,int y1,int x2,int y2,int sz)
// 当前棋盘左上角(x1,y1)
// 当前棋盘中特殊方格位置(x2,y2)
// 当前棋盘大小sz*sz
{
if(sz==1)return;
int t=++tot; // 这里一定要用一个变量把tot先记下来,否则计数会出错!
//因为tot继续递归,将会增加,返回到本层的时候实际上要填的数应该是原来的tot
sz/=2;// 缩小棋盘
int midx=x1+sz-1;
int midy=y1+sz-1;
// 当前棋盘的中心靠左上位置(midx,midy)
// 1
if(x2<=midx&&y2<=midy) // 特殊方格在左上部分,继续划分
{
solve(x1,y1,x2,y2,sz);
}
else
{
ans[midx][midy]=t; // 不在左上,覆盖左上部分的右下角
solve(x1,y1,midx,midy,sz); // 继续划分
}
// 2
if(x2<=midx&&y2>midy) // 特殊方格在右上部分,继续划分
{
solve(x1,y1+sz,x2,y2,sz);
}
else
{
ans[midx][midy+1]=t; // 不在右上,覆盖右上部分的左下角
solve(x1,y1+sz,midx,midy+1,sz); // 继续划分
}
// 3
if(x2>midx&&y2<=midy) // 特殊方格在左下部分,继续划分
{
solve(x1+sz,y1,x2,y2,sz);
}
else
{
ans[midx+1][midy]=t; // 不在左下,覆盖左下部分的右上角
solve(x1+sz,y1,midx+1,midy,sz); // 继续划分
}
// 4
if(x2>midx&&y2>midy) // 特殊方格在右下部分,继续划分
{
solve(x1+sz,y1+sz,x2,y2,sz);
}
else
{
ans[midx+1][midy+1]=t; // 不在右下,覆盖右下部分的左上角
solve(x1+sz,y1+sz,midx+1,midy+1,sz); // 继续划分
}
}
int main()
{
ios::sync_with_stdio(false);
cin>>k>>bx>>by;
n=(1<<k); //2^k
solve(1,1,bx,by,n);
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++)
j==n?printf("%d\n",ans[i][j]):printf("%d ",ans[i][j]);
return 0;
}
/*
3
1 1
ans:
0 3 4 4 8 8 9 9
3 3 2 4 8 7 7 9
5 2 2 6 10 10 7 11
5 5 6 6 1 10 11 11
13 13 14 1 1 18 19 19
13 12 14 14 18 18 17 19
15 12 12 16 20 17 17 21
15 15 16 16 20 20 21 21
*/
具体的手工模拟过程可参考此文:棋盘覆盖问题-分治法