棋盘覆盖问题详解(分治,非递归)

(代码由 java 编写)

1.问题描述


如图(a)所示,k>0时,有一个2k×2k的棋盘,棋盘中任意位置有一个特殊的方格,要求利用图(b)中的4中L型骨牌覆盖图(a)除特殊方格以外的区域,要求所有区域都要覆盖,并且骨牌不能重叠。

2.解题思路

可将2k×2k的棋盘划分为4个2k-1×2k-1的子棋盘。这样划分后,由于原棋盘只有一个特殊方格,所以,这4个子棋盘中只有一个子棋盘包含该特殊方格,其余3个子棋盘中没有特殊方格。为了将这3个没有特殊方格的子棋盘转化为特殊棋盘,以便采用递归方法求解,可以用一个L型骨牌覆盖这3个较小棋盘的会合处,如图(b)所示,从而将原问题转化为4个较小规模的棋盘覆盖问题。递归地使用这种划分策略,直至将棋盘分割为1×1的子棋盘。

这一大堆文字是不是看着就很难受,那就别看了,

假设有一个8*8的棋盘,初始位置(2,7)处有一个棋子,那么如何填充呢,简单点说对于一共就三步

①:把nn的棋盘分成四个n/2 * n/2的小棋盘(例子中也就是分成四个44的棋盘)

②:把没有棋子的棋盘块上放上棋子,放到四个棋盘块接壤的角落(本例中也就是(4,4)(5,4)(5,5))

③:再把分出的小棋盘块再次调用上面两步,如果子棋盘长宽=2,那么直接填满

听懂了那我就直接上代码

import java.util.Scanner;public class 棋盘覆盖 {public static int i=1;public static int QP[][];public static void main(String[] args) {Scanner scanner=new Scanner (System.in);int size = scanner.nextInt ();QP=new int[size][size];int ZuoBiaoX = scanner.nextInt ()-1;int ZuoBiaoY = scanner.nextInt ()-1;棋盘覆盖 (0,0,ZuoBiaoX,ZuoBiaoY,size);Print (QP);}public static void 棋盘覆盖(int tx,int ty ,int qx ,int qy,int size){int numqxqy=QP[qx][qy];if (size==2){QP[tx][ty]=i;QP[tx+1][ty]=i;QP[tx][ty+1]=i;QP[tx+1][ty+1]=i;QP[qx][qy]=numqxqy;i++;return;}else {int sizeA=size/2;int qx1 = tx+sizeA-1, qx2 = tx+sizeA, qx3 = tx+sizeA-1, qx4 = tx+sizeA, qy1 = ty +sizeA-1, qy2 = ty +sizeA-1, qy3 = ty +sizeA, qy4 = ty +sizeA;if (qx<=tx+sizeA-1){if (qy<=ty+size-1){qx1=qx;qy1=qy;QP[qx2][qy2]=i;QP[qx3][qy3]=i;QP[qx4][qy4]=i;i++;}else {qx3=qx;qy3=qy;QP[qx2][qy2]=i;QP[qx1][qy1]=i;QP[qx4][qy4]=i;i++;}}else {if (qy<=ty+size-1){qx2=qx;qy2=qy;QP[qx1][qy1]=i;QP[qx3][qy3]=i;QP[qx4][qy4]=i;i++;}else {qx4=qx;qy4=qy;QP[qx2][qy2]=i;QP[qx3][qy3]=i;QP[qx1][qy1]=i;i++;}}棋盘覆盖 (tx,ty,qx1,qy1,sizeA);棋盘覆盖 (tx+sizeA,ty,qx2,qy2,sizeA);棋盘覆盖 (tx,ty+sizeA,qx3,qy3,sizeA);棋盘覆盖 (tx+sizeA,ty+sizeA,qx4,qy4,sizeA);}}public static void Print(int Num[][]){for (int i =0;i<Num.length;i++){for (int j =0;j<Num[0].length;j++){System.out.print (Num[i][j]+"\t");}System.out.println ();}}
}

接下来我们解释一下这个代码

首先创建一个全局变量QP,这个二维数组代表着我们的棋盘,二维数组上相同的数字就是我们的L形骨牌,i代表着我们填入期盼的棋子,一般三个一填,因为三个棋子构成一个L型骨牌。

public static int i=1;
public static int QP[][];

获取输入,size就是棋盘大小,ZuoBiaoX就是初始棋子的横坐标,ZuoBiaoY就是初始棋子的纵坐标。为什么要-1呢,在数组中是从0开始,实际我们习惯的计数是从1开始。

Scanner scanner=new Scanner (System.in);
int size = scanner.nextInt ();
QP=new int[size][size];
int ZuoBiaoX = scanner.nextInt ()-1;
int ZuoBiaoY = scanner.nextInt ()-1;

之后调用我们的棋盘覆盖方法,这个方法遵循了刚才说的三步

如果size==2,那就直接给棋盘剩下的三个格子填满i,然后return。

if (size==2){QP[tx][ty]=i;QP[tx+1][ty]=i;QP[tx][ty+1]=i;QP[tx+1][ty+1]=i;QP[qx][qy]=numqxqy;i++;return;
}

否则我们把棋盘分成四块,先把中心接壤部分填上L型骨牌

int sizeA=size/2;
int qx1 = tx+sizeA-1, qx2 = tx+sizeA, qx3 = tx+sizeA-1, qx4 = tx+sizeA,
qy1 = ty +sizeA-1, qy2 = ty +sizeA-1, qy3 = ty +sizeA, qy4 = ty +sizeA;
if (qx<=tx+sizeA-1){if (qy<=ty+size-1){qx1=qx;qy1=qy;QP[qx2][qy2]=i;QP[qx3][qy3]=i;QP[qx4][qy4]=i;i++;}else {qx3=qx;qy3=qy;QP[qx2][qy2]=i;QP[qx1][qy1]=i;QP[qx4][qy4]=i;i++;}
}
else {if (qy<=ty+size-1){qx2=qx;qy2=qy;QP[qx1][qy1]=i;QP[qx3][qy3]=i;QP[qx4][qy4]=i;i++;}else {qx4=qx;qy4=qy;QP[qx2][qy2]=i;QP[qx3][qy3]=i;QP[qx1][qy1]=i;i++;}

然后分别对四个子棋盘递归,也就是16 * 16变四个 8 * 8,然后变16个4 * 4,然后变32个2 * 2,然后这32个2 * 2分别填满。

棋盘覆盖 (tx,ty,qx1,qy1,sizeA);
棋盘覆盖 (tx+sizeA,ty,qx2,qy2,sizeA);
棋盘覆盖 (tx,ty+sizeA,qx3,qy3,sizeA);
棋盘覆盖 (tx+sizeA,ty+sizeA,qx4,qy4,sizeA);

最后调用函数输出

public static void Print(int Num[][]){for (int i =0;i<Num.length;i++){for (int j =0;j<Num[0].length;j++){System.out.print (Num[i][j]+"\t");}System.out.println ();}
}

我们来看一下输出,基本上没什么问题,如果看了我的帖子还是没看明白,搞个4*4的棋盘按照上面的几步走一遍就懂了。

3.时间复杂度

这个的时间复杂度还是挺难算的

首先假设来了的2k*2k的棋盘,设T(k)是覆盖一个2^k * 2^k棋盘所需的时间,则从算法的分治策略可知,T(k)满足如下递归方程:

当k=1就是1*1的棋盘时间复杂度就是1,所以时间复杂度就是4^k

那么在看k*k的棋盘上,时间复杂度就是4log2k=2k

4.棋盘覆盖非递归算法

Hanoi塔问题是经典的递归算法,按照栈内元素出一进三的思想(具体解题方法可以参考{(27条消息) 汉诺塔Java递归和非递归算法解析_Addam Holmes的博客-CSDN博客})那么我们的棋盘覆盖问题可以用栈模拟递归吗。

Of course Yes!!!!!!!!

先上代码

import java.util.Scanner;
import java.util.Stack;public class 棋盘覆盖非递归 {public static int i=1;public static int QP[][];public static void main(String[] args) {Scanner scanner=new Scanner (System.in);int size = scanner.nextInt ();QP=new int[size][size];int ZuoBiaoX = scanner.nextInt ()-1;int ZuoBiaoY = scanner.nextInt ()-1;Stack<QPState> stack = new Stack<> ();QPState QP1 = new QPState (0,0,ZuoBiaoX,ZuoBiaoY,size);stack.push (QP1);//首元素入栈while (stack.size ()>0){QPState QPLinShi = stack.pop ();if(QPLinShi.size==2){int numqxqy=QP[QPLinShi.qx][QPLinShi.qy];QP[QPLinShi.tx][QPLinShi.ty]=i;QP[QPLinShi.tx+1][QPLinShi.ty]=i;QP[QPLinShi.tx][QPLinShi.ty+1]=i;QP[QPLinShi.tx+1][QPLinShi.ty+1]=i;QP[QPLinShi.qx][QPLinShi.qy]=numqxqy;i++;}else {int sizeA=QPLinShi.size/2;int qx1 = QPLinShi.tx+sizeA-1;int qx2 = QPLinShi.tx+sizeA;int qx3 =QPLinShi. tx+sizeA-1;int qx4 = QPLinShi.tx+sizeA;int qy1 = QPLinShi.ty +sizeA-1;int qy2 = QPLinShi.ty +sizeA-1;int qy3 = QPLinShi.ty +sizeA;int qy4 = QPLinShi.ty +sizeA;if (QPLinShi.qx<=QPLinShi.tx+sizeA-1){if (QPLinShi.qy<=QPLinShi.ty+size-1){qx1=QPLinShi.qx;qy1=QPLinShi.qy;QP[qx2][qy2]=i;QP[qx3][qy3]=i;QP[qx4][qy4]=i;i++;}else {qx3=QPLinShi.qx;qy3=QPLinShi.qy;QP[qx2][qy2]=i;QP[qx1][qy1]=i;QP[qx4][qy4]=i;i++;}}else {if (QPLinShi.qy<=QPLinShi.ty+size-1){qx2=QPLinShi.qx;qy2=QPLinShi.qy;QP[qx1][qy1]=i;QP[qx3][qy3]=i;QP[qx4][qy4]=i;i++;}else {qx4=QPLinShi.qx;qy4=QPLinShi.qy;QP[qx2][qy2]=i;QP[qx3][qy3]=i;QP[qx1][qy1]=i;i++;}}QPState QPLinShi1 = new QPState (QPLinShi.tx,QPLinShi.ty,qx1,qy1,sizeA);QPState QPLinShi2 = new QPState (QPLinShi.tx+sizeA,QPLinShi.ty,qx2,qy2,sizeA);QPState QPLinShi3 = new QPState (QPLinShi.tx,QPLinShi.ty+sizeA,qx3,qy3,sizeA);QPState QPLinShi4 = new QPState (QPLinShi.tx+sizeA,QPLinShi.ty+sizeA,qx4,qy4,sizeA);}}for (int i =0;i<QP.length;i++){for (int j =0;j<QP[0].length;j++){System.out.print (QP[i][j]+"\t");}System.out.println ();}}
}
class QPState{int tx;int ty;int qx;int qy;int size;public QPState(int tx,int ty ,int qx ,int qy,int size){this.tx = tx;this.ty = ty;this.qx = qx;this.qy = qy;this.size = size;}
}

解释一下这个代码吧,作为一个面向对象语言,学java不会用对象那毫无疑问,学的毫无意义,对象使得java在某些地方变得非常适合写算法。在这个题我们也用到这个方法,要用栈模拟递归,所以我们需要对栈内元素进行某些设定。设置一个类QPState,这个类代表着一个原棋盘的子棋盘。tx,ty是子棋盘左下角在原来的大棋盘上的坐标,qx,qy是子棋盘上已有棋子的坐标,size是子棋盘的大小。

class QPState{int tx;int ty;int qx;int qy;int size;public QPState(int tx,int ty ,int qx ,int qy,int size){this.tx = tx;this.ty = ty;this.qx = qx;this.qy = qy;this.size = size;}
}

继续啊,定义一个栈,获取到的元素封装成刚才定义的QPState,然后入栈

int size = scanner.nextInt ();
QP=new int[size][size];
int ZuoBiaoX = scanner.nextInt ()-1;
int ZuoBiaoY = scanner.nextInt ()-1;
Stack<QPState> stack = new Stack<> ();
QPState QP1 = new QPState (0,0,ZuoBiaoX,ZuoBiaoY,size);

之后当有size=2的子棋盘就输出,否则就按照之前说多的方式一变四。

 while (stack.size ()>0){QPState QPLinShi = stack.pop ();if(QPLinShi.size==2){int numqxqy=QP[QPLinShi.qx][QPLinShi.qy];QP[QPLinShi.tx][QPLinShi.ty]=i;QP[QPLinShi.tx+1][QPLinShi.ty]=i;QP[QPLinShi.tx][QPLinShi.ty+1]=i;QP[QPLinShi.tx+1][QPLinShi.ty+1]=i;QP[QPLinShi.qx][QPLinShi.qy]=numqxqy;i++;}else {int sizeA=QPLinShi.size/2;int qx1 = QPLinShi.tx+sizeA-1;int qx2 = QPLinShi.tx+sizeA;int qx3 =QPLinShi. tx+sizeA-1;int qx4 = QPLinShi.tx+sizeA;int qy1 = QPLinShi.ty +sizeA-1;int qy2 = QPLinShi.ty +sizeA-1;int qy3 = QPLinShi.ty +sizeA;int qy4 = QPLinShi.ty +sizeA;if (QPLinShi.qx<=QPLinShi.tx+sizeA-1){if (QPLinShi.qy<=QPLinShi.ty+size-1){qx1=QPLinShi.qx;qy1=QPLinShi.qy;QP[qx2][qy2]=i;QP[qx3][qy3]=i;QP[qx4][qy4]=i;i++;}else {qx3=QPLinShi.qx;qy3=QPLinShi.qy;QP[qx2][qy2]=i;QP[qx1][qy1]=i;QP[qx4][qy4]=i;i++;}}else {if (QPLinShi.qy<=QPLinShi.ty+size-1){qx2=QPLinShi.qx;qy2=QPLinShi.qy;QP[qx1][qy1]=i;QP[qx3][qy3]=i;QP[qx4][qy4]=i;i++;}else {qx4=QPLinShi.qx;qy4=QPLinShi.qy;QP[qx2][qy2]=i;QP[qx3][qy3]=i;QP[qx1][qy1]=i;i++;}}QPState QPLinShi1 = new QPState (QPLinShi.tx,QPLinShi.ty,qx1,qy1,sizeA);QPState QPLinShi2 = new QPState (QPLinShi.tx+sizeA,QPLinShi.ty,qx2,qy2,sizeA);QPState QPLinShi3 = new QPState (QPLinShi.tx,QPLinShi.ty+sizeA,qx3,qy3,sizeA);QPState QPLinShi4 = new QPState (QPLinShi.tx+sizeA,QPLinShi.ty+sizeA,qx4,qy4,sizeA);}}
}}QPState QPLinShi1 = new QPState (QPLinShi.tx,QPLinShi.ty,qx1,qy1,sizeA);QPState QPLinShi2 = new QPState (QPLinShi.tx+sizeA,QPLinShi.ty,qx2,qy2,sizeA);QPState QPLinShi3 = new QPState (QPLinShi.tx,QPLinShi.ty+sizeA,qx3,qy3,sizeA);QPState QPLinShi4 = new QPState (QPLinShi.tx+sizeA,QPLinShi.ty+sizeA,qx4,qy4,sizeA);}}

最后输出。
```for (int i =0;i<QP.length;i++){for (int j =0;j<QP[0].length;j++){System.out.print (QP[i][j]+"\t");}System.out.println ();}

棋盘覆盖问题详解(递归)相关推荐

  1. 棋盘覆盖问题——详解(C++)

    [问题描述] 在一个 2 ^k × 2 ^k 个方格组成的棋盘中,若有一个方格与其他方格不同,则称该方格为一特殊方格,且称该棋盘为一个特殊棋盘.显然特殊方格在棋盘上出现的位置有4^k 种情形.因而对任 ...

  2. php详解递归,PHP递归算法详解

    本篇文章主要介绍PHP递归算法详解,感兴趣的朋友参考下,希望对大家有所帮助. 遇到需要设计树节点的数据库结构,以及需要读出来的树节点数据结构!大家是否会选择用数据库的查询方式来获取树结构呢?//曾经的 ...

  3. java方法不可覆盖_详解Java构造方法为什么不能覆盖,我的钻牛角尖病又犯了.......

    一 看Think in Java,遇到个程序 classEgg2 {protected classYolk {publicYolk() { System.out.println("Egg2. ...

  4. 自定义ElementUI风格树形组件,详解递归组件的使用及事件数据传递,视图更新等问题

    组件视图样式 当我们做多级菜单或者权限列表管理的时候,大多会采用树形结构来实现,有的朋友为了省事,不想多费脑力,多费时间,直接几层for循环就做了个差不多的树形组件,更省事的朋友直接拿ElementU ...

  5. 汉诺塔代码图文详解(递归入门)

    游戏规则: 已知条件 存在A,B,C三根柱子,A上套有N片圆盘 (如下图) 目的 将A上的所有圆盘移到C上 约束条件 每次只能移动一片圆盘,且整个过程中只能出现小圆盘在大圆盘之上的情况 首先我们模拟( ...

  6. Java SE 第八十八,八十九,九十讲 递归深度剖析 IO流深入详解,递归作业详解

    1.所谓递归(Recursion),就是方法调用自身,对于递归来说,一定有一个出口,让递归结束,只有这样才能保证不出现死循环. 2.作业:给定任意一个目录,以树形方式展现该目录中所有子目录和文件.另外 ...

  7. Python学习(类的属性、继承、覆盖等详解)

    Tips:如果是从基础部分一路跟着过来的朋友,需要告诉你们的是我偷偷吧编程工具PyCharm装上了,今天算是进入面向对象编程环节.本人使用的编程工具是PyCharm,未安装的可以先去官网下载安装.下面 ...

  8. 汉诺塔问题详解 递归实现 C语言

    目录 一.前言 二.游戏规则 三.思路讲解 四.完整代码 五.最终结果展示 一.前言 汉诺塔:汉诺塔(Tower of Hanoi)源于印度传说中,大梵天创造世界时造了三根金钢石柱子,  其中一根柱子 ...

  9. 详解递归,文+图+代码,带你轻松了解递归算法的设计思路(附汉诺塔分析及题解)

    递归,从代码实现上来看就是函数的自我调用,即在函数体中再调用函数本身.如: void dg(int i){if(i>10)return;//递归出口cout<<i;//可以是其他语句 ...

最新文章

  1. Java并发之公平锁
  2. Docker官方Centos镜像下安装Elasticsearch【详细步骤】
  3. Java8 Stream 数据流,大数据量下的性能效率怎么样?
  4. cuda学习笔记1 - hello world实战
  5. java ssh客户端_简单的Java SSH客户端
  6. 如何在Mac上访问 USB 驱动器?
  7. javaweb简单源代码_Java Web轻松学39 - JSP核心原理
  8. protues仿真8086常见问题
  9. 代码坏味道 之 17 狎昵关系 inappropriate intimacy
  10. matlab处理各种数据、文件
  11. 矩阵关于26的模逆matlab,给定加密矩阵在模运算下的逆矩阵.ppt
  12. 因为此版本的应用程序不支持其项目类型(.csproj)”之解
  13. vbulletin论坛_评论-vBulletin 3.0
  14. EasyExcel解析动态表头及导出
  15. 我为何一直强调外包公司别去
  16. android note4 android版本,三星Galaxy Note4手机系统是什么?能升级安卓4.3吗?
  17. CoffeeScript for循环处理
  18. 稀疏索引、密集索引、聚簇索引、非聚簇索引
  19. 安装H3C Cloud Lab(HCL)时遇到的问题及解决办法汇总
  20. docker-comose搭建sonarqube 及 maven项目使用

热门文章

  1. 7-Web安全——SQL注入WAF绕过之注释符号
  2. 数字孪生厦门隧道,打造智慧交通闭环行车安全体系 | 图扑软件
  3. 测试网站漏洞软件,如何检测网站漏洞,web漏洞扫描工具盘点
  4. 乙肝两对半的五项指标
  5. 今日学到:Day 2
  6. webx URIBrokerService 总结
  7. 全景自动切片技术-krpano初识
  8. 智慧城市交通系列之行人、车辆属性识别方案设计
  9. 什么是通达信服务接口?
  10. SOLIDWORKS官方认证考试