递归与分治——棋盘覆盖(全过程c++代码)

问题描述

分治的技巧在于如何划分棋盘,使划分后的子棋盘的大小相同,并且每个子棋盘均包含一个特殊方格,从而将原问题分解为规模较小的棋盘覆盖问题。k>0时,可将2k×2k的棋盘划分为4个2(k-1)×2(k-1)的子棋盘。由于原棋盘只有一个特殊方格,即4个子棋盘中只有一个子棋盘包含该特殊方格,其余3个子棋盘中没有特殊方格。为了将这3个没有特殊方格的子棋盘转化为特殊棋盘,以便采用递归方法求解,可以用一个L型骨牌覆盖这3个较小棋盘的会合处,从而将原问题转化为4个较小规模的棋盘覆盖问题。递归地使用这种划分策略,直至将棋盘分割为1×1的子棋盘。

算法解析

①每次将棋盘划分为四块,分别检索四块棋盘中是否含有特殊的方块。如果有就继续检索;如果没有就将靠近原棋盘中心的最小方块认为是特殊方块(用step进行标记),然后逐步检索,当所有的方块被标记后就完成了对整个期盼的覆盖。

//覆盖左上角 
	if(targetX<topLeftX+s&&targetY<topLeftY+s){
		coverMap(topLeftX,topLeftY,targetX,targetY,s);//特殊方块在左上角 
	}
	else{
		map[topLeftX+s-1][topLeftY+s-1]=tmp;
		coverMap(topLeftX,topLeftY,topLeftX+s-1,topLeftY+s-1,s);
	}
		
	//覆盖右上角
	if(targetX>topLeftX+s-1&&targetY<topLeftY+s) {
		coverMap(topLeftX+s,topLeftY,targetX,targetY,s);
	}
	else{
		map[topLeftX+s][topLeftY+s-1]=tmp;
		coverMap(topLeftX+s,topLeftY,topLeftX+s,topLeftY+s-1,s);
	}
	
	//覆盖左下角
	if(targetX<topLeftX+s&&targetY>topLeftY+s-1) {
		coverMap(topLeftX,topLeftY+s,targetX,targetY,s);
	}
	else{
		map[topLeftX+s-1][topLeftY+s]=tmp;
		coverMap(topLeftX,topLeftY+s,topLeftX+s-1,topLeftY+s,s);
	}
	
	//覆盖右下角
	if(targetX>topLeftX+s-1&&targetY>topLeftY+s-1) {
		coverMap(topLeftX+s,topLeftY+s,targetX,targetY,s);
	}
	else{
		map[topLeftX+s][topLeftY+s]=tmp;
		coverMap(topLeftX+s,topLeftY+s,topLeftX+s,topLeftY+s,s);
	}

②每次划分以棋盘大小作为划分的基准,通过方块的坐标辅助判断特殊方块是否在某个棋盘内。
不断地二分,缩小棋盘的大小,直到被划分成最小方块就结束递归。

	if(size==1)return;
	int s=size/2;//更改划分基准 

③通过递归调用,每层递归都同时处理左上、右上、左下、右下四个方位的检索,其中仅有一个方位可能存在特殊方块。剩余的三个方位的交界处的最小方块会被分别标记成特殊方块(每层的step值是不变的,不同递归层的step值不同),这样便实现了以L形覆盖整个棋盘。

	int tmp = step![在这里插入图片描述](https://img-blog.csdnimg.cn/20210621110548136.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L2ZyZWV6aW5nXzAw,size_16,color_FFFFFF,t_70#pic_center)
++; //step自加,实现不同的L形覆盖 

④结果展示
特殊方块从0开始标记,随着step的自加标记值也随之改变。

代码

void coverMap(int topLeftX,int topLeftY,int targetX,int targetY,int size){//棋盘左上角坐标;特殊方块坐标;当前棋盘大小 
	if(size==1)return;
	int s=size/2;//更改划分基准 
	int tmp = step++; //step自加,实现不同的L形覆盖 
	 
	//覆盖左上角 
	if(targetX<topLeftX+s&&targetY<topLeftY+s){
		coverMap(topLeftX,topLeftY,targetX,targetY,s);//特殊方块在左上角 
	}
	else{
		map[topLeftX+s-1][topLeftY+s-1]=tmp;
		coverMap(topLeftX,topLeftY,topLeftX+s-1,topLeftY+s-1,s);
	}
		
	//覆盖右上角
	if(targetX>topLeftX+s-1&&targetY<topLeftY+s) {
		coverMap(topLeftX+s,topLeftY,targetX,targetY,s);
	}
	else{
		map[topLeftX+s][topLeftY+s-1]=tmp;
		coverMap(topLeftX+s,topLeftY,topLeftX+s,topLeftY+s-1,s);
	}
	
	//覆盖左下角
	if(targetX<topLeftX+s&&targetY>topLeftY+s-1) {
		coverMap(topLeftX,topLeftY+s,targetX,targetY,s);
	}
	else{
		map[topLeftX+s-1][topLeftY+s]=tmp;
		coverMap(topLeftX,topLeftY+s,topLeftX+s-1,topLeftY+s,s);
	}
	
	//覆盖右下角
	if(targetX>topLeftX+s-1&&targetY>topLeftY+s-1) {
		coverMap(topLeftX+s,topLeftY+s,targetX,targetY,s);
	}
	else{
		map[topLeftX+s][topLeftY+s]=tmp;
		coverMap(topLeftX+s,topLeftY+s,topLeftX+s,topLeftY+s,s);
	}
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

freezing?

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值