Algorithm之Tromino谜题

Tromino谜题

1.1 题目描述

Tromino是指一个由棋盘上的三个方块组成的L型骨牌。如何用Tromino覆盖一个缺少了一个方块(可以在棋盘上任何位置)的棋盘(下图展示了情况)。除了这个缺失的方块,Tromino应该覆盖棋盘上的所有方块,Tromino可以任意转向但不能有重叠。
在这里插入图片描述

1.2 问题分析与解决思路

1.2.1 问题分析

问题需要解决如何用Tromino覆盖这个除了缺失的方块位置外的2nx2n的棋盘的所有方块(n为大于0的任意整数)。可以通过将问题规模扩大或缩小的方式,将棋盘换成2x2或者4x4,
2x2的棋盘:
在这里插入图片描述
可以看出,这个缺失的方块无论在哪个位置,都可以使用Tromino去覆盖其余位置
4x4的棋盘:
在这里插入图片描述
可以将4x4的棋盘分成4个小的2x2的棋盘,可以发现,在4x4棋盘中,划分后的2x2的棋盘只有一个是含有缺失的方块的,其余是没有的,此时,我们需要对其他没有缺失的方块的2x2的棋盘进行处理。

1.2.2解决思路

划分可以想到分治法,分治法的思想就是把一个大问题划分为数个同样结构的小问题,再加以解决,然后合并。对于Tromino谜题,就是将一个大棋盘划分数个小棋盘,且每个小棋盘都要有缺块。以大棋盘的中心点为原点划分成等大的四个象限,每个象限为一个小棋盘。对于缺块,例如:在4x4的棋盘中为没有缺块的小棋盘,分配一个缺块,缺块都选择是每个棋盘靠近中心点的那块,此时这三个新划分的缺块组成了Tromino。于是可以想到每个象限都有一个区域被覆盖,再对每个象限中其他三个区域覆盖一个Tromino,则这个象限全部都覆盖了。对于缺块区域,覆盖一个Tromino也符合题目要求。因此对于任意n的大小的棋盘,可以通过分治法,对于这题,是象限分割的方法,对棋盘进行处理,划分为最简单的2x2,然后合并,从而实现整个棋盘的覆盖。

1.3 模型建立与算法描述

记棋盘的长度为n,缺失区域的棋盘坐标为(x,y)
将上述分析过程和解决思路进一步归纳为以下几步:
1.给定二维数组来存储棋盘,以坐标方式存储缺块的大小,这样就需要L型骨牌覆盖时的区域,用一个一维数组存储,
2.将棋盘划分为四个象限,判断缺块在哪个象限
3.使用L型骨牌进行覆盖
4.重复2,3步,直到棋盘所有位置被覆盖
算法伪代码描述:

算法 Tromino(A[][],x1,y1,n,x,y,f[])
//递归调用Tromino,对棋盘进行象限分割,然后覆盖
//输入:二维数组A[][],棋盘左下角坐标(x1,y1),棋盘长度n,缺块区域的坐标(x,y),L型骨牌区域覆盖的块数的f[]
//输出:被L型骨牌区域完全覆盖的的A[][]
int a[][],int x1,int y1
int n,int x ,int y ,int f[]
i=n/2
if  i-1 = =0
 if  缺块在第一象限
    将f[]++赋予A[][]的第二、三、四象限靠近原点的数组
  else if 缺块在第二象限
    将f[]++赋予A[][]的第一、三、四象限靠近原点的数组
else if 缺块在第三象限
    将f[]++赋予A[][]的第一、二、四象限靠近原点的数组
else
    将f[]++赋予A[][]的第一、二、三象限靠近原点的数组
else
  if 缺块在第一象限
      将f[]++赋予A[][]的第二、三、四象限靠近原点的数组
      Tromino(第一象限) //函数覆盖第一象限
Tromino(第二象限) //函数覆盖第二象限
Tromino(第三象限) //函数覆盖第三象限
Tromino(第四象限) //函数覆盖第四象限
  else if 缺块在第二象限
      将f[]++赋予A[][]的第一、三、四象限靠近原点的数组
      Tromino(第一象限) //函数覆盖第一象限
Tromino(第二象限) //函数覆盖第二象限
Tromino(第三象限) //函数覆盖第三象限
Tromino(第四象限) //函数覆盖第四象限
   else if 缺块在第三象限
      将f[]++赋予A[][]的第一、二、四象限靠近原点的数组
      Tromino(第一象限) //函数覆盖第一象限
Tromino(第二象限) //函数覆盖第二象限
Tromino(第三象限) //函数覆盖第三象限
Tromino(第四象限) //函数覆盖第四象限
else
      将f[]++赋予A[][]的第一、二、三象限靠近原点的数组
      Tromino(第一象限) //函数覆盖第一象限
Tromino(第二象限) //函数覆盖第二象限
Tromino(第三象限) //函数覆盖第三象限
Tromino(第四象限) //函数覆盖第四象限

1.4 算法实现与复杂度分析

1.4.1 算法实现

算法使用的数据结构为数组
算法实现的步骤
1.找到棋盘的中心位置,判断该棋盘上缺块的位置,以此为依据,将棋盘按四个象限的方式等份划分
2.除去含有缺块的象限,对另外三个象限进行处理,在原点位置加一个Tromino,然后在每个象限中根据缺块的位置,继续等份划分
3.重复1,2步,直到棋盘划分为1x1(或2x2)结束。

1.4.2 算法复杂度分析

问题规模为2nx2n,每次递归调用函数会执行(2nx2n)次递归停止判断。
设T(n)是覆盖一个2nx2n的棋盘所需的时间,从算法的分治法策略可以得出,T(n)满足以下递推式:
在这里插入图片描述
解此递推式可以得出T(n)=Θ(4n)
因此此算法的时间复杂度为Θ(4n)
由于使用了递归分治法,程序会使用堆栈来保存上一次递归的情况,直到合并为止,所以空间复杂度4n+(1x4+4x4+…+4n-1),即Θ(4n)。

1.5 程序实现及运行结果分析

![在这里插入图片描述](https://img-blog.csdnimg.cn/2020012614355013.png
在这里插入图片描述在这里插入图片描述在这里插入图片描述在这里插入图片描述在这里插入图片描述在这里插入图片描述
分析:这是8x8的棋盘,由图可以看到缺块是粉色,1x1的大小,在(1,1)的位置,覆盖时先判断缺块位置,再覆盖其他不含有缺块的象限,刚好构成一个L型骨牌,再从第二象限(即左上角区域)到第一象限(即右上角区域)到第三象限(即左下角区域),最后是第四象限(即右下角区域)覆盖。依次递归地覆盖,直到棋盘所有位置的方块都被覆盖。
我在长度那里设置了2的幂次的集合{1,2,4,8,16,32,64,128,256},棋盘的长度可以取这个集合里的数,缺块的位置可以设置它的坐标(X,Y)来改变。

相关代码源码

  • 4
    点赞
  • 18
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

daisyr07

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

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

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

打赏作者

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

抵扣说明:

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

余额充值