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

问题描述

在一个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;
}



猜你喜欢

转载自blog.csdn.net/Dante__Alighieri/article/details/70311909