棋盘覆盖问题分治递归求解

棋盘覆盖算法(分治法) 棋盘覆盖问题是指在一个 2k×2k 的棋盘上,缺失一个格子,要求用 L 形的三格骨牌覆盖整个棋盘,使得每个格子都被覆盖且没有重叠。以下是详细的算法实现,包括原理、步骤、图示法表示步骤、代码关键行注释和时间复杂度。棋盘覆盖算法通过分治法,将棋盘分成更小的子棋盘,并递归地处理每个子棋盘,最终覆盖整个棋盘。该算法的时间复杂度为指数级别,适用于中小规模的棋盘覆盖问题。假设我们有一个 4×4 的棋盘,缺失的格子位于 (2,2)。步骤 2:递归处理子棋盘。3. 图示法表示步骤。4. 代码关键行注释。 阅读详情
AI摘要

本文详细阐述了棋盘覆盖问题的解决思路与算法实现,利用递归方法将大棋盘分解为子棋盘,通过L型骨牌覆盖特殊棋盘上的非特殊方格,直至棋盘简化为1×1。

棋盘覆盖问题描述

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

求解思路

当k>0时,将2k×2k棋盘分割为4个2k-1×2k-1 子棋盘(a)所示。
特殊方格必位于4个较小子棋盘之一中,其余3个子棋盘中无特殊方格。为了将这3个无特殊方格的子棋盘转化为特殊棋盘,可以用一个L型骨牌覆盖这3个较小棋盘的会合处,如 (b)所示,从而将原问题转化为4个较小规模的棋盘覆盖问题。
递归地使用这种分割,直至棋盘简化为棋盘1×1。

在这里插入图片描述

问题求解

下面介绍棋盘覆盖问题中数据结构的设计:

  • (1)棋盘:用二维数组Board[size][size]表示一个棋盘, Board[0][0]是棋盘的左上角方格。其中,size=2k 。为了在递归处理的过程中使用同一个棋盘,将数组Board设为全局变量;
  • (2)子棋盘:在棋盘数组Board[size][size]中,由子棋盘左上角的下标tr、tc和棋盘边长s表示;
  • (3)特殊方格:用Board[dr][dc]表示,dr和dc是该特殊方格在棋盘数组Board中的下标;
  • (4)L型骨牌:一个2k×2k的棋盘中有一个特殊方格,所以用到L型骨牌的个数为(4k-1)/3将所有L型骨牌从1开始连续编号,用一个全局整型变量tile表示,其初始值为0。要全部覆盖棋盘需要(4k-1)/3个L型骨牌。
    在这里插入图片描述

算法描述

执行4次if-else语句,每次调用都将棋盘划分成四个大小相同的子区域棋盘。
当棋盘大小为1时,递归出口。

int title =1;//用作标记L型骨牌编号
int a[101][101];//用以表示棋盘
//tr,tc表示棋盘的起始位置(第tr行,第tc列),dr,dc表示特殊格子所在位置(第dr行,第dc列),4*4的棋盘tr,tc取值范围为0,1,2,3
//size表示棋盘大小,4*4的棋盘size为4
void ChessBoard(int tr,int tc,int dr,int dc,int size)
{
    if(size==1)  return;//递归出口
    
    int s = size/2;
    int t = title++;
    //如果特殊点的位置在左上方
    if(dr<tr+s&&dc<tc+s){
        ChessBoard(tr,tc,dr,dc,s);
    }else{
        //填充其右下角格子
        a[tr+s-1][tc+s-1] = t;
        ChessBoard(tr,tc,tr+s-1,tc+s-1,s);
    }
    //如果特殊点的位置在右上方
    if(dr<tr+s&&dc>=tc+s){
        ChessBoard(tr,tc+s,dr,dc,s);
    }else{
        //填充其左下角格子
        a[tr+s-1][tc+s] = t;
        ChessBoard(tr,tc+s,tr+s-1,tc+s,s);
    }
    //如果特殊点的位置在左下方
    if(dr>=tr+s&&dc<tc+s){
        ChessBoard(tr+s,tc,dr,dc,s);
    }else{
        //填充其右上角格子
        a[tr+s][tc+s-1] = t;
        ChessBoard(tr+s,tc,tr+s,tc+s-1,s);
    }
    //如果特殊点的位置在右下方
    if(dr>=tr+s&&dc>=tc+s){
        ChessBoard(tr+s,tc+s,dr,dc,s);
    }else{
        //填充其左上角格子
        a[tr+s][tc+s] = t;
        ChessBoard(tr+s,tc+s,tr+s,tc+s,s);
    }
}

输入输出

在这里插入图片描述输入

输入有一行,分别为M,x,y
M表示棋盘宽度(M=2k)
x表示棋盘所在的行数
y表示棋盘所在的列数

输出

输出有M行,即输出棋盘,棋盘中每个小格占2个字符间距

样例输入

8 2 3
表示8*8的棋盘,特殊点在第2行,第3列的位置上

样例输出
在这里插入图片描述

完整代码

#include <iostream>
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
using namespace std;
int title =1;//用作标记L型骨牌编号
int a[101][101];//用以表示棋盘
//tr,tc表示棋盘的起始位置(第tr行,第tc列)
//dr,dc表示特殊格子所在位置(第dr行,第dc列),4*4的棋盘tr,tc取值范围为0,1,2,3
//size表示棋盘大小,4*4的棋盘size为4
void ChessBoard(int tr,int tc,int dr,int dc,int size)
{
    if(size==1)  return;//递归出口

    int s = size/2;
    int t = title++;
    //如果特殊点的位置在左上方
    if(dr<tr+s&&dc<tc+s){
        ChessBoard(tr,tc,dr,dc,s);
    }else{
        //填充其右下角格子
        a[tr+s-1][tc+s-1] = t;
        ChessBoard(tr,tc,tr+s-1,tc+s-1,s);
    }
    //如果特殊点的位置在右上方
    if(dr<tr+s&&dc>=tc+s){
        ChessBoard(tr,tc+s,dr,dc,s);
    }else{
        //填充其左下角格子
        a[tr+s-1][tc+s] = t;
        ChessBoard(tr,tc+s,tr+s-1,tc+s,s);
    }
    //如果特殊点的位置在左下方
    if(dr>=tr+s&&dc<tc+s){
        ChessBoard(tr+s,tc,dr,dc,s);
    }else{
        //填充其右上角格子
        a[tr+s][tc+s-1] = t;
        ChessBoard(tr+s,tc,tr+s,tc+s-1,s);
    }
    //如果特殊点的位置在右下方
    if(dr>=tr+s&&dc>=tc+s){
        ChessBoard(tr+s,tc+s,dr,dc,s);
    }else{
        //填充其左上角格子
        a[tr+s][tc+s] = t;
        ChessBoard(tr+s,tc+s,tr+s,tc+s,s);
    }
}
int main()
{
    int size;
    //cout<<"请输入棋盘大小:";
    scanf("%d",&size);
    //初始化
    for(int i=0;i<size;i++)
        for(int j=0;j<size;j++)
            a[i][j] = 0;
    //cout<<"特殊点所在位置为:";
    int x,y;
    cin>>x>>y;
    ChessBoard(0,0,x-1,y-1,size);//因为chessBoard算法是从0行,0列开始算起的,所以对输入的x,y都进行自减操作
    //输出棋盘
    for(int i=0;i<size;i++)
    {
        for(int j=0;j<size;j++)
            printf("%2d ",a[i][j]);
        printf("\n");
    }
    return 0;
}

运行结果

在这里插入图片描述

算法时间复杂度分析

设T(k)为覆盖2k*2k棋盘的时间, (1)k=0 覆盖它需要常数时间O(1) (2)k>0
测试哪个子棋盘特殊以及形成3个特殊子棋盘需要O(1) 覆盖4个特殊子棋盘需四次递归调用,共需时间4T(k-1)

在这里插入图片描述
所以棋盘覆盖的时间复杂度为O(4k)。

算法实验——递归与分治   一、实验目的: 理解递归算法的思想和递归程序的执行过程,并能熟练编写递归程序。 掌握分治算法的思想,对给定的问题能设计出分治算法予以解决。 具体要求: 1. 分析并掌握“棋盘覆盖问题”的递归与分治算法示例; 2. 练习使用递归与分治策略求解具体问题; 二、实验环境: Visual C++ 实验环境 三、实验内容: (写出主要的内容) 1. 1) 编写完整的主函数,分别记... 阅读详情

相关推荐

三大算法之一:分治法(带你用分治法思想优化程序,计算降低复杂算法的时间复杂度)

1.排序 1.排序的概念 排序是计算中经常进行的一系列操作,其目的是将一组“无序”的记录序列调整为“有序”的记录序列。简单来说 无序->有序。 通常情况下排序分为两种:内部排序,外部排序 1.内部排序 若整个排序的过程中不需要访问外存便能完成,则成这类问题为内部排序。 2.外部排序 若参与排序的数据数量过大,整个序列排序过程中不可能在内存中完成,则称此类排序为外部排序。 我们主要讨论的是内部排序的各种方法。 2.排序的流程 1.排序流程 1.得到n个记录数据的序列为{R1,R2,

分享学习的知识,记录我的技术成长道路 2万+

算法第五周

快速幂算法,棋盘覆盖问题

2203_75434527的博客 983

递归与分治策略深度解析及实战应用

特征递归写法迭代模拟代码简洁性高较低空间复杂度O(n) 调用栈O(n) 显式栈可读性直观反映数学定义需理解状态机逻辑可调试性调用栈天然可见需打印自定义栈内容性能函数调用开销大控制流更紧凑适用语言所有支持函数的语言更适合不支持深度递归的语言综上所述,递归与迭代各有优劣。在开发初期,建议优先使用递归表达逻辑;在性能测试发现问题后,再考虑转换为迭代形式或引入记忆化缓存进行优化。

weixin_42561464的博客 887

棋盘覆盖问题(分治)

问题描述:在一个2k∗2k(k>0)2^k*2^k(k>0)2k∗2k(k>0)的棋盘,只有一个与其它方格不同的特殊方格,现在要用下图所示的 L 形骨牌覆盖除了特殊方格外的其它全部方格,任意两骨牌不能重叠,给出一种覆盖方法。 本题可以将大棋盘划分为四个大小相同的象限,那么这个特殊方格必定存在其中一个象限,根据方格存在的不同象限,L 形骨牌的摆法: 这样便能使被划分的四个象限均存在一个“特殊的方格”,达到分治的条件。 分治一个最重要的特点在于一个复杂的大问题可以分解为几个性质或求解思路相

atwdy的博客 1516

西南交通大学算法分析与设计实验报告 - 棋盘覆盖问题.docx

在一个2^k*2^k个方格组成的棋盘中,恰有一个方格与其他方格不同,称该方格为特殊方格。棋盘覆盖问题要求下图四种不同形状的L型骨牌覆盖给定棋盘上除特殊方格以外的所有方格,且任意2个L型骨牌不得重叠覆盖。 (仅供参考,请独立完成实验)

Supervisor 安装与使用

一、Supervisor 介绍 Supervisor 是一个用 Python 编写的进程管理工具,它可以用于监控和控制类 UNIX 操作系统上的多个进程。它是一个客户端/服务器系统,其中 Supervisor 的服务器端称为 supervisord,负责启动管理的子进程、响应客户端命令、重启崩溃或退出的子进程、记录子进程的 stdout 和 stderr 输出,以及处理子进程生命周期中的事件。客...

疯子丶pony的博客 3863

手把手教会你-棋盘覆盖算法以及代码实现!!

在一个2k×2k (k≥0)个方格组成的棋盘中,恰有一个方格与其他方格不同,称该方格为特殊方格。 棋盘覆盖问题要求用如图(b)所示的L型骨牌覆盖给定棋盘上除特殊方格以外的所有方格,且骨牌之间不得有重叠。 (a) k=2时的一种棋盘 (b) 4种不同形状的L型骨牌 分析题目: 当看k>0时,将2k×2k ...

qq_53344479的博客 2671

【PyTorch版本兼容性指南】如何在不同版本中正确使用torch.nn.attention

本文详细解析了PyTorch版本兼容性问题,特别是torch.nn.attention模块在不同版本中的使用差异。针对常见的ModuleNotFoundError错误,提供了三种实用解决方案:升级PyTorch版本、使用自定义实现和源码移植方案,并分享了最佳实践建议,帮助开发者有效避免兼容性问题。

weixin_29084231的博客 472

分治法解决棋盘覆盖

在一个2k*2k个方格组成的棋盘中,若恰有一个方格与其他方格不同,则称该方格为一特殊方格,且称该棋盘为一特殊棋盘。特殊方格在棋盘出现的位置有4k种情形 在棋盘覆盖问题中。有4种不同形态的L型骨牌覆盖在一个给定的棋盘上除特殊方块外的其他所有方格上,且任意2个L型骨牌不得重叠覆盖。 所以,在任何一个2k*2k的棋盘覆盖中,用到的L星骨牌个数恰为 (4k-1)/3 我们需要实现在确定特殊方格位置后设计L骨牌棋盘覆盖的形式位置将一个规模为n的问题分解为k个规模较小的子问题,这些子问题互相独立且与原问题相同。递归地解

weixin_53113130的博客 3178

STM32L452与FPGA通信翻车?手把手教你关闭I2C时钟延展避坑(附OVR错误解决方案)

本文深入解析STM32L452与FPGA在I2C通信中因时钟延展功能导致的常见问题,提供关闭I2C时钟延展的详细配置方法(NOSTRETCH模式),并针对可能出现的OVR错误给出Combined模式解决方案。通过实战案例和波形分析,帮助工程师快速排查和解决嵌入式系统中的I2C兼容性问题。

e3f4g5的博客 215

飞塔防火墙和paloalto防火墙构建ipsec

一、配置fortigate防火墙1.防火墙配置上网功能1.1配置fortigate的wan1接口IP为100.100.100.2/24VLAN交换internal,IP地址为192.168.156.99/24。开启DHCP分配IP地址范围为192.168.156.110-192.168.156.2101.2配置访问互联网的缺省路由1.3配置访问互联网的安全策略2.配置与Paloalto防火墙的IPSECVPN。

weixin_44675999的博客 3739

分治法求解棋盘覆盖问题

当 k>0 时,将 2^k * 2^k 棋盘分割为 4 个 2^(k-1) * 2^(k - 1)子棋盘,如下图(f)所示。为了将这 3 个无特殊方格的子棋盘转化为特殊棋盘,可以用一个 L 型骨牌覆盖这 3 个较小棋盘的会合处,如下图(g)所示。分治的技巧在于如何划分棋盘,使划分后的子棋盘的大小相同,并且每个子棋盘均包含一个特殊方格,从而将原问题分解为规模较小的棋盘覆盖问题。棋盘覆盖问题是指在一个大小为2n * 2n的棋盘上,去掉其中一个方格后,用L型骨牌(覆盖3个方格)将其完全覆盖。

m0_63144319的博客 673

C# 基于NetStandard.Opc.Ua实现高效OPC UA数据订阅与同步读写

本文详细介绍了在C#中利用NetStandard.Opc.Ua库高效实现OPC UA数据订阅与同步读写的方法。通过实战代码演示了如何建立连接、配置订阅管理器、优化监控项分组,并对比了同步与异步读写的适用场景,帮助工业软件开发者构建稳定可靠的数据采集客户端,提升工业物联网应用开发效率。

weixin_29201859的博客 228

算法设计与分析笔记-分治法

分治法基本思想: 将一个难以直接解决的大问题,划分成一些规模较小的子问题,以便各个击破,分而治之。更一般地说,将要求解的原问题划分成k个较小规模的子问题,对这k个子问题分别求解。如果子问题的规模仍然不够小,则再将每个子问题划分为k个规模更小的子问题,如此分解下去,直到问题规模足够小,很容易求出其解为止,再将子问题的解合并为一个更大规模的问题的解,自底向上逐步求出原问题的解。 求解过程: ...

qq_45653661的博客 306

避坑指南:群晖DSM 7.X挂载NTFS硬盘,为什么你的SATA口不行?从原理到实战一次讲清

本文深入解析群晖DSM 7.X系统挂载NTFS硬盘的底层原理与实战排查方法,揭示SATA接口权限配置的关键参数(如esataportcfg和internalportcfg),并提供安全修改端口配置的详细步骤。针对不同型号群晖NAS的配置差异,给出替代方案与常见故障排查技巧,帮助用户解决NTFS硬盘挂载问题。

weixin_26757925的博客 256

基于LightGBM和多模型融合的量化交易研究:沪深300为例【附代码】

📊 数据科学与大数据专业 | 数据分析与模型构建 | 数据驱动决策✨ 专业领域:数据挖掘与清洗大数据处理与存储技术机器学习与深度学习模型数据可视化与报告生成分布式计算与云计算数据安全与隐私保护💡 擅长工具:Python/R/Matlab 数据分析与建模Hadoop/Spark 大数据处理平台SQL数据库管理与优化Tableau/Power BI 数据可视化工具TensorFlow/PyTorch 深度学习框架✅数据科学与大数据技术毕业论文【数据】

lagougongzuoshi的博客 1670

算法:棋盘覆盖问题

如何应用分治法求解棋盘覆盖问题呢?分治的技巧在于如何划分棋盘,使划分后的子棋盘的大小相同,并且每个子棋盘均包含一个特殊方格,从而将原问题分解为规模较小的棋盘覆盖问题。k>0时,可将2k×2k的棋盘划分为4个2(k-1)×2(k-1)的子棋盘,如图4.11(a)所示。这样划分后,由于原棋盘只有一个特殊方格,所以,这4个子棋盘中只有一个子棋盘包含该特殊方格,其余3个子棋盘中没有特殊方格。为了将这...

顾道长生的科研笔记 4937

1.4 KFD 设备文件的获取与驱动握手协议

本文分析了OpenClose模块中libhsakmt与KFD内核驱动建立通信的过程。首先通过hsaKmtOpenKFD()函数打开/dev/kfd设备文件,建立用户态与内核态的通信通道。随后通过AMDKFD_IOC_GET_VERSION ioctl命令完成版本握手,确认双方的接口兼容性。KFD驱动采用Major.Minor二级版本号体系,当前主要版本为1,从1.1演进到1.19不断添加新功能。整个过程构成了用户态与内核态之间的"建连协议",是所有后续GPU操作的基础前提。

图形/计算GPU的驱动与虚拟化技术分享园地 607

算法设计与分析——递归与分治策略

文章目录1. 递归算法1.1 特点1.2 优缺点2. 分治策略2.1 基本思想2.2 适用的条件2.3 求解过程(步骤)3. 典型算法案例3.1 二分搜索3.1.1 非递归实现3.1.1 递归实现3.2 棋盘覆盖问题 1. 递归算法 1.1 特点 1.2 优缺点 优点:结构清晰、可读性强 缺点:运行时效率较低,耗费较多的时间、空间资源 2. 分治策略 2.1 基本思想 分治策略的基本思想是将一个规模为n的问题分解为k个较小的子问题,这些子问题互相独立,并且和原问题相同,递归

krain的博客 3566

IMSL CNL 7.0.0 (x86-64)Crack

IMSL CNL 7.0.0 (x86-64)Crack intel的算法库破解文件,这是C++版本的破解文件

数学建模模型总结

这是本人在两年内准备参加数学建模竞赛搜集到的模型资料,已经经过了本人的筛选和整理,希望能够对准备参加数学建模竞赛的学弟学妹们提供一些帮助!

【算法设计与分析】实验2:递归与分治—Hanoi塔、棋盘覆盖、最大子段和

在设计递归算法时,必须明确递归基准条件和递归表达式。递归基准条件是递归的终止条件,决定了递归何时停止,否则代码不会有输出结果。在Hanoi塔问题的设计中,我注意到了递归调用的顺序和参数的传递方式,确保递归能够正确进行。

m0_73970214的博客 1156

SAP B1中文培訓教材_SDK

公司内部培训资料,对开发工具 ,DIAPI, UIAPI,Add-ON有详细解说

用分治法求解组合问题(最大子段和问题、棋盘覆盖问题)

一、求解最大子段和问题 (1)问题描述 (2)蛮力法求解 long maxSubSum1(int a[],int n) { int i,j,k;   long maxSum=a[0],thisSum;   for (i=0;i<n;i++) //两重循环穷举所有的连续子序列   { for (j=i;j<n;j++)     { thisSum=0;  ...

wmy01234的博客 2282

汉书HE8,好用的汇编代码编写工具

汉书HE8,好用的汇编代码编写工具早期编写汇编代码所用功能强大

大学生课程|算法分析与设计|实验项目练习(全部)

大学生课程|算法分析与设计|课后练习(全部)

久菜盒子工作室的博客 1156

棋盘覆盖问题

棋盘覆盖三种实现方法详解

cxiaodi的博客 4814

分治法解决棋盘覆盖、循环赛日程表、快速排序、归并排序

标题说到分治,就不得不先提递归了 递归算法:直接或者间接调用自身的算法称为递归算法。 设计步骤: 分析问题、寻找递归关系; 设置边界、控制递归; 设计函数、确定参数。 接下来看一个递归的例子:递归解决全排列问题 引用问题描述:设R={r1,r2,…,rn}是要进行排列的n个元素,求R的全排列Perm(R)。 问题分析: 设(ri)perm(X)表示在全排列perm(X)的每一个排列前加上前缀得到的排列。 解决方案: 1.递归关系:perm(R)由(r1)perm(R1),(r2)perm(R2)

HangHug_L的博客 836

分治法思想的介绍(大整数的乘法,Strassen矩阵乘法,棋盘覆盖问题,二分搜索,快速排序,合并排序,线性时间选择)

分治法基本思想 将一个难以直接解决的大问题,分割成一些规模较小的k个相同问题,以便·各个击破,分而治之·。 对这k个子问题分别求解。如果子问题的规模仍然不够小,则再划分为若干个子问题,如此递归的进行下去,直到问题规模足够小,很容易求出其解为止。 将求出的小规模的问题的解合并为一个更大规模的问题的解,自底向上逐步求出原来问题的解。  递归是实现分治算法思想的技术。????查看递归的介绍  合并排序的例子 分治法的适用条件 分治法所能解决的问题一般具有以下几个特征: 该问题的规模缩小到一定的程度就可以

迷雾总会解 1898

算法分析与设计之分治算法

分治算法(divide and conquer)的核心思想:分而治之 ,即将原问题划分成 个规模较小,并且结构与原问题相似的独立子问题,递归地解决这些子问题,然后再合并其结果,就得到原问题的解。

风间琉璃的博客 1143
上一篇: n的全排列分治递归求解
下一篇: 合并排序分治递归求解
practical_sharp
博客等级 码龄8年 499粉丝 148原创
评论 3
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值