[分治,递归]棋盘覆盖问题

来源:互联网 发布:淘宝关键词权重怎么刷 编辑:程序博客网 时间:2024/06/02 07:29

问题描述

在一个2^k×2^k 个方格组成的棋盘中,恰有一个方格与其他方格不同,称该方格为一特殊方格,且称该棋盘为一特殊棋盘。在棋盘覆盖问题中,要用图示的4种不同形态的L型骨牌覆盖给定的特殊棋盘上除特殊方格以外的所有方格,且任何2个L型骨牌不得重叠覆盖。

输入:给定k(1<=k<=10),表示棋盘大小为  2^k×2^k     ,在给出特殊方格坐标x,y(0<=x,y<=1024)。

输出,一个边长为2^k的方阵,特殊方格编号0,所有骨牌从1开始编号,数据间间隔TAB。

样例输入:2 0 1

样例输出:

2    0    3    3

2    2    1    3

4    1    1    5

4    4    5    5



分析:

           该题关键在于如何划分各L型骨牌所在位置区域。我们发现,L型骨牌占三个方格,我们可以把棋盘从中央分为四块,那么这四块子棋盘中仅一块是有特殊方格的,可以用一块骨牌使得其他三块子棋盘均被覆盖。以此为原则,无论这种分法是否最终可解,我们首先保证了每个子棋盘都有一个特殊方格,所以,分治的模型就出来了。

           我们可以用递归来完成分治的任务。每次递归divide(zx,zy,si,x,y),(zx,zy)为子棋盘左上角坐标,si为子棋盘大小,因为棋盘总为正方形,所以si为边长,那么前3个参数就确定了子棋盘的位置和大小;(x,y)表示子棋盘中特殊方格的位置,这个位置是由上层递归分配骨牌后决定的。以此为标准。

递归流程为:

①判断边界,若当前棋盘大小为1,则无法再分割,递归结束。

②定子棋盘中心位置。

③判断特殊方格所在位置(左上,右上,左下,或右下)。

④根据特殊方格位置确定所选L型骨牌,原特殊方格和三个L型骨牌的方格分别为四个子棋盘的特殊方格。

⑤依据④中判断,按编号填充棋盘。

⑥4次递归,分别对应四个子棋盘。


代码如下:(代码为本人手打,限于算法理解能力,代码可读性不强)

#include<iostream>#include<algorithm>#include<cstdio>#include<cstring>#include<cmath>using namespace std;int K,X,Y,row=1;int ch[1030][1030];int now=1;//骨牌编号。void divide(int zx,int zy,int si,int x,int y)//zx,zy为当前棋盘左上角坐标,si为棋盘大小,x,y为已覆盖的棋盘位置。{if(si==1) return;int mx,my,mid;mid=si/2;//分割得新棋盘大小。mx=zx+si/2-1;//中间点。my=zy+si/2-1;/*for(int i=1;i<=row;i++){for(int j=1;j<=row;j++) printf("%d ",ch[i][j]);printf("\n");}cout<<endl;*/if(x>mx&&y>my)//分四种情况讨论,得出已覆盖的点在棋盘中的位置,再判断取哪个{ch[mx][my]=ch[mx+1][my]=ch[mx][my+1]=now;now++;divide(zx,zy,mid,zx+mid-1,zy+mid-1);divide(zx,zy+mid,mid,zx+mid-1,zy+mid);divide(zx+mid,zy,mid,zx+mid,zy+mid-1);divide(zx+mid,zy+mid,mid,x,y);}if(x>mx&&y<=my){ch[mx][my]=ch[mx][my+1]=ch[mx+1][my+1]=now;now++;divide(zx,zy,mid,zx+mid-1,zy+mid-1);divide(zx,zy+mid,mid,zx+mid-1,zy+mid);divide(zx+mid,zy,mid,x,y);divide(zx+mid,zy+mid,mid,zx+mid,zy+mid);} if(x<=mx&&y>my){ch[mx][my]=ch[mx+1][my]=ch[mx+1][my+1]=now;now++;divide(zx,zy,mid,zx+mid-1,zy+mid-1);divide(zx,zy+mid,mid,x,y);divide(zx+mid,zy,mid,zx+mid,zy+mid-1);divide(zx+mid,zy+mid,mid,zx+mid,zy+mid);}if(x<=mx&&y<=my){ch[mx+1][my+1]=ch[mx+1][my]=ch[mx][my+1]=now;now++;divide(zx,zy,mid,x,y);divide(zx,zy+mid,mid,zx+mid-1,zy+mid);divide(zx+mid,zy,mid,zx+mid,zy+mid-1);divide(zx+mid,zy+mid,mid,zx+mid,zy+mid);}}int main(){scanf("%d%d%d",&K,&X,&Y);X++;Y++;ch[X][Y]=0;for(int i=1;i<=K;i++) row*=2;divide(1,1,row,X,Y);for(int i=1;i<=row;i++){for(int j=1;j<=row;j++) printf("%d\t",ch[i][j]);printf("\n");}return 0;}



0 0
原创粉丝点击