2k*2k 棋盘覆盖问题

棋盘覆盖问题

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

图示:
在这里插入图片描述
实例:
在这里插入图片描述
2. 基本思路:
关注的重点是特殊方格,2k2k的棋盘上如果没有特殊点,那么L型骨牌不可能完全覆盖,那么我们分治的思路是,每一个父棋盘分解为4个相同大小的子棋盘,除了本身就有特殊点的一个子棋盘,为另外三个棋盘人工设置3个特殊点,以此满足递归条件;基本情况是11棋盘,直接返回。

  1. 算法
//tr,tc为当前棋盘的左上角行号列号,dr,dc为特殊点行号列号,size是大小
CHSEEBOARD (tr, tc, dr, dc, size):
	if size==1 return
//tile是一个全局变量,它不满足递归,用于对人工设置的三个特殊点标记相同的数字
	t=++tile
//左上角
	if dr<tr+s && dc<tc+s
		CHESSBOARD (tr, tc, dr, dc, s)
	else
		board[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+s, tc, dr, dc, s)
	else
		board[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, tc+s, dr, dc, s)
	else
		board[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+s, dr, dc, s)
	else
		board[tr+s-1][tc+s-1] = t;
		CHESSBOARD (tr+s, tc+s, tr+s, tc+s, s);

  1. 复杂度:O(n^2)
    T(1)=1
    T(n)=4T(n/2)+1
    =>T(n)=O(n^2)

  2. 运行截图
    8*8棋盘
    在这里插入图片描述

  3. 源代码

#include <iostream>
#include <vector>
#include <iomanip>
using namespace std;

int tile = 0;
void chessBoard(vector<vector<int>> & board,int tr, int tc, int dr, int dc, int size)
{
	if(size==1)	return;
	int t = ++tile;
	int s = size/2;
	//左上 
	if(dr<tr+s && dc<tc+s)
		chessBoard(board,tr,tc,dr,dc,s);
	else
	{
		board[tr+s-1][tc+s-1] = t;
		chessBoard(board,tr,tc,tr+s-1,tc+s-1,s);
	}
	//左下 
	if(dr>=tr+s && dc<tc+s)
		chessBoard(board,tr+s,tc,dr,dc,s);
	else
	{
		board[tr+s][tc+s-1] = t;
		chessBoard(board,tr+s,tc,tr+s,tc+s-1,s);
	}
	//右上 
	if(dr<tr+s && dc>=tc+s)
		chessBoard(board,tr,tc+s,dr,dc,s);
	else
	{
		board[tr+s-1][tc+s] = t;
		chessBoard(board,tr,tc+s,tr+s-1,tc+s,s);
	}
	//右下 
	if(dr>=tr+s && dc>=tc+s)
		chessBoard(board,tr+s,tc+s,dr,dc,s);
	else
	{
		board[tr+s][tc+s] = t;
		chessBoard(board,tr+s,tc+s,tr+s,tc+s,s);
	}
}

void Print(const vector<vector<int>> &board)
{
	int n= board.size();
	for(int i=0;i<n;i++)
	{
		for(int j=0;j<n;j++)
		{
			cout<<setw(2)<<left<<board[i][j]<<" ";
		}
		cout<<endl;
	}
}

int main(int argc, char** argv) {
	vector<vector<int>> board;
	board.resize(8);
	for(int i=0;i<board.size();i++)
	{
		board[i].resize(8);
	}
	board[3][3] = 0;
	chessBoard(board,0,0,3,3,board.size());
	Print(board);	
	return 0;
}

注:文章中的示例及L型骨牌图片来自于
https://blog.csdn.net/yew1eb/article/details/8776985

  • 4
    点赞
  • 37
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
棋盘覆盖问题分治算法的正确性可以通过数学归纳法来证明。首先,我们可以将棋盘分成四个大小相等的子棋盘,然后将L型骨牌放在其一个棋盘心的方格上。接着,我们可以将问题转化为对剩余三个子棋盘棋盘覆盖问题进行递归求解。由于每个子棋盘的大小都是原棋盘大小的1/2,因此递归求解的次数为log2n,其n为原棋盘的大小。 在每一层递归,我们都可以将棋盘分成四个大小相等的子棋盘,并将L型骨牌放在其一个棋盘心的方格上。由于每个L型骨牌覆盖了一个黑色和一个白色的方格,因此每个子棋盘心的方格必须是白色的。因此,我们可以将每个子棋盘心的方格标记为白色,并将其余方格标记为黑色。这样,我们就可以将棋盘覆盖问题转化为对黑色方格的覆盖问题进行递归求解。 在递归求解的过程,我们可以使用归纳法证明每个子棋盘都可以被完美地覆盖。首先,对于原棋盘的四个角落,它们都是黑色的,因此它们必须被覆盖。由于每个L型骨牌覆盖了一个黑色和一个白色的方格,因此我们可以将每个子棋盘心的方格一个L型骨牌覆盖,从而覆盖了四个角落。接着,我们可以使用归纳法假设每个大小为2k x 2k的子棋盘都可以被完美地覆盖,然后证明每个大小为2k+1 x 2k+1的子棋盘也可以被完美地覆盖。 对于一个大小为2k+1 x 2k+1的子棋盘,它可以被分成四个大小为2k x 2k的子棋盘和四个大小为2k x 1的矩形。由于每个矩形都包含一个黑色和一个白色的方格,因此它们必须被覆盖。由于每个大小为2k x 2k的子棋盘都可以被完美地覆盖,因此我们可以使用归纳假设将它们覆盖。接着,我们可以将四个L型骨牌放在四个大小为2k x 1的矩形心的方格上,从而覆盖了整个子棋盘。 综上所述,棋盘覆盖问题分治算法的正确性可以通过数学归纳法来证明。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值