实验一:棋盘覆盖问题
一、问题描述:
在一个2k×2k个方格组成的棋盘中,若恰有一个方格与其他方格不同,则称该方格为特殊方格。显然,特殊方格在棋盘上出现的位置有4k种情形。下图是k=2时16个特殊棋盘中的一个。
在棋盘覆盖问题中,要用图示的 4 种不同形态的L型骨牌覆盖一个给定的特殊棋盘上除特殊方格以外的所有方格,且任何 2 个L型骨牌不得重叠覆盖。易知,在任何一个2k×2k的棋盘覆盖中,用到的L型骨牌个数恰为(4k-1)/3。
二、实验环境:
系统:Windows 10
IDE:Visual Studio 2022
编译语言:C++
三、程序代码与结果分析:
(1)解决问题策略:分治策略
当k>0时,将2k×2k 棋盘分割为4个2k-1×2k-1个子棋盘,如下图所示。特殊方格必位于 4 个较小子棋盘之一中,其余3 个子棋盘中无特殊方格。为了将这 3 个无特殊方格的子棋盘转化为特殊棋盘,可以用一个L 型骨牌覆盖这 3 个小棋盘的回合处。由此,问题转化成了 4 个规模较小的棋盘覆盖问题。
(2)棋盘覆盖问题中数据结构的设计
棋盘:用二维数组board[size][size]表示一个棋盘,其中size=2^k.为了在递归处理的过程中使用同一个棋盘,将数组board设为全局变量
子棋盘:在棋盘数组board[size][size]中,由子棋盘左上角的下标tr,tc和棋盘边长s表示
特殊方格:用board[dr][dc]表示,dr和dc是该特殊方格在棋盘数组board中的下标
L型骨牌:一个2k×2k的棋盘中有一个特殊方格,所以,用到L型骨牌的个数为(4k-1)/3,将所有L型骨牌从1开始连续编号,用一个全局变量tile表示。
说明:
整形二维数组Board表示棋盘,Board[0][0]为棋盘的左上角方格。
tile是一个全局整形变量,用来表示L形骨牌的编号,初始值为0。
tr:棋盘左上角方格的行号;
tc:棋盘左上角方格的列号;
dr:特殊方格所在的行号;
dc:特殊方格所在的列号;
size:size=2k,棋盘规格为2k×2k。
(3)伪代码
Input:棋盘的规模,特殊方格的坐标
Output:使用L型骨牌覆盖好的棋盘
骨牌编号t随使用次数递增;
if 特殊方格在左上角棋盘中
递归覆盖非特殊方格的其余方格;
else
{
使用t号骨牌覆盖右下角;
递归覆盖其余方格;
}
if 特殊方格在右上角棋盘中
递归覆盖非特殊方格的其余方格;
else
{
使用t号骨牌覆盖左下角;
递归覆盖其余方格;
}
if 特殊方格在左下角棋盘中
递归覆盖非特殊方格的其余方格;
else
{
使用t号骨牌覆盖右上角;
递归覆盖其余方格;
}
if 特殊方格在右下角棋盘中
递归覆盖非特殊方格的其余方格;
else
{
使用t号骨牌覆盖左上角;
递归覆盖其余方格;
}
(4)代码运行结果实例
三、实验中遇到的问题以及实验体会:
这次实验我们主要学习了分治法处理问题,通过这次实验,我对分治法有了更深刻的体会。
分治法所能解决的问题一般具有以下几个特征:
1、该问题的规模缩小到一定的程度就可以容易地解决
因为问题的计算复杂性一般是随着问题规模的增加而增加,大部分问题满足这个特征。
2、该问题可以分解为若干个规模较小的相同问题
这条特征是应用分治法的前提,它也是大多数问题可以满足的,此特征反映了递归思想的应用
3、利用该问题分解出的子问题的解可以合并为该问题的解
能否利用分治法完全取决于问题是否具有这条特征,如果具备了前两条特征,;而不具备第三条特征,则可以考虑贪心算法或动态规划。
4、该问题所分解出的各个子问题是相互独立的,即子问题之间不包含公共的子问题
如果各子问题是不独立的,则分治法要做许多不必要的工作,重复地解公共的子问题,此时虽然也可用分治法,但一般用动态规划较好。
在实验过程中我也同样遇到了许多问题,最开始初始化的时候,由于没有正确定义棋盘的二位数组,导致程序出现异常,在成功修改数据后结果运行出来。
完整实验代码加格式化报告请见如下连接下载:
https://download.csdn.net/download/dxxmsl/86951599
> 更多博客内容访问我的博客网站:https://www.xsblog.site/