【算法】分治法的应用——棋盘覆盖问题

创作不易,本篇文章如果帮助到了你,还请点赞 关注支持一下♡><)!!
主页专栏有更多知识,如有疑问欢迎大家指正讨论,共同进步!
更多算法分析与设计知识专栏:算法分析
给大家跳段街舞感谢支持!ጿ ኈ ቼ ዽ ጿ ኈ ቼ ዽ ጿ ኈ ቼ ዽ ጿ ኈ ቼ ዽ ጿ ኈ ቼ


目录

  • 一、问题描述
  • 二、问题分析
  • 三、代码实现
  • 四、复杂度分析

一、问题描述

在一个2k×2k个方格组成的棋盘中,恰有一个方格与其它方格不同,称该方格为特殊方格,且称该棋盘为特殊棋盘

在棋盘覆盖问题中,要用图示的4种不同形态的L型骨牌覆盖给定的特殊棋盘上除特殊方格以外的所有方格,且任何2个L型骨牌不得重叠覆盖。

【算法】分治法的应用——棋盘覆盖问题_第1张图片

(证明该问题有解):

数学归纳法(mathematical induction)
当n=1时(2×2棋盘),该问题有解
假设当n=k时(2k×2k棋盘),该问题有解
那么当n=k+1时(2k+1×2k+1棋盘),将棋盘划分为2k×2k子棋盘,特殊方格位于4个子棋盘之一中,余3个子棋盘中无特殊方格

二、问题分析

利用分治法需要满足分治的条件

目前不符合将一个大问题分解成若干个与原问题相似的小问题,需要将问题进行转化

现在需要考虑如何将棋盘分为几个相同的子棋盘

我们可以将棋盘沿着它的中心进行划分,这样可以保证每个子棋盘的大小都是相同的

【算法】分治法的应用——棋盘覆盖问题_第2张图片

【算法】分治法的应用——棋盘覆盖问题_第3张图片

但是分出的棋盘中没有特殊方格,并不是特殊棋盘

如何将这3个无特殊方格的子棋盘转化为特殊棋盘?

用一个L型骨牌覆盖这3个较小棋盘的会合处,将原问题转换为`4个n=k`时的子问题,因为n=k时有解,所以n=k+1时也有解。

特殊方格必位于4个较小子棋盘之一中,其余3个子棋盘中无特殊方格。为了将这3个无特殊方格的子棋盘转化为特殊棋盘,可以用一个L型骨牌覆盖这3个较小棋盘的会合处

从而将原问题转化为4个较小规模的棋盘覆盖问题。递归地使用这种分割,直至棋盘简化为棋盘1×1

【算法】分治法的应用——棋盘覆盖问题_第4张图片

三、代码实现

#include
using namespace std;

int box[100][100];
int num = 0;
void chessBoard(int x, int y, int a, int b, int length) 
{
	//如果棋盘简化为1×1,该方格为一特殊方格
	if (length == 1)
	{  
		return;
	}
	int h = length / 2;   //分割棋盘为原来的一半
	int t = ++num;        //L型骨牌号,从1开始
	//左上角
	if (a < x + h && b < y + h)
	{   //特殊方格在此棋盘中
		chessBoard(x, y, a, b, h);   
	}else
	{   //覆盖右下角的方格再划分
		box[x + h - 1][y + h - 1] = t;
		chessBoard(x, y, x + h - 1, y + h- 1, h);
	}
	//右上角
	if (a < x + h && b >= y + h)
	{  //特殊方格在此棋盘中
		chessBoard(x, y + h, a, b, h);
	}else
	{   //覆盖右下角的方格再划分
		box[x + h - 1][y + h] = t;
		chessBoard(x, y + h, x + h - 1, y + h, h);
	}
	//右下角
	if (a >= x + h && b >= y + h)
	{  //特殊方格在此棋盘中
		chessBoard(x + h, y + h, a, b, h);
	}else
	{   //覆盖右下角的方格再划分
		box[x + h][y + h] = t;
		chessBoard(x + h, y + h, x + h, y + h, h);
	}
	//左下角
	if (a >= x + h && b < y + h)
	{  //特殊方格在此棋盘中
		chessBoard(x + h, y, a, b, h);
	}else
	{   //覆盖右下角的方格再划分
		box[x + h][y + h - 1] = t;
		chessBoard(x + h, y, x + h, y + h - 1, h);
	}
}

int main()
{
	//左上角方格:1行1列,特殊方格:4行2列,棋盘为8×8
	chessBoard(1, 1, 4, 2, 8);
	for (int i = 1; i <= length; i++)
	{
		for (int j = 1; j <= length; j++)
		{
			cout << box[i][j];
		}
		cout << endl;
	}
	return 0;
}

四、复杂度分析

由于覆盖一个2k×2k棋盘所需的L型骨牌个数为(4k-1)/3,故上述算法是一个渐近意义下的最优算法

【算法】分治法的应用——棋盘覆盖问题_第5张图片


大家的点赞、收藏、关注将是我更新的最大动力! 欢迎留言或私信建议或问题。
大家的支持和反馈对我来说意义重大,我会继续不断努力提供有价值的内容!如果本文哪里有错误的地方还请大家多多指出(●'◡'●)

你可能感兴趣的:(算法分析,算法,开发语言,学习,笔记)