分治策略——棋盘覆盖问题

一.问题描述

一个2k*2k的棋盘,指定一点为特殊方格(无需覆盖),然后用(4k-1)/3个L型骨牌无重叠地覆盖其余所有方格。下图为一个示例:

在这里插入图片描述

二.算法思想——分治策略

将一个规模为n问题分为k个规模较小的子问题,这些子问题互相独立且与原问题相同,递归或迭代地解这些子问题,再将子问题合并得到原问题的解。

以一个实例说明棋盘覆盖问题的分治思想。

在这里插入图片描述

上图为 2 3 ∗ 2 3 2^3*2^3 2323的棋盘,黑色方格为指定特殊方格。

第一次分割后形成4个 2 2 ∗ 2 2 2^2*2^2 2222的棋盘,需要为没有特殊方格的棋盘指定特殊方格(保证子问题互相独立且与原问题相同),即黄色的1部分(这样指定刚好是一个L型骨牌)。

第二次分割以右上角 2 2 ∗ 2 2 2^2*2^2 2222棋盘为例,分割后形成4个2*2的棋盘,同样为没有特殊方格的棋盘指定特殊方格(白色的2部分)。

最终,2*2的棋盘再覆盖一次即可完成。在指定特殊方块的过程中,问题规模也越来越小,依次完成上左、上右、下左、下右四个期棋盘的覆盖(顺序可任意规定)后,大棋盘的覆盖也就随之完成。

代码实现可分为三步:分割棋盘(规模缩小一倍),判定特殊方格的位置(将特殊方格的坐标与棋盘中间坐标对比)、根据比较结果决定对应棋盘用不用增添特殊方格。

3.算法时间复杂度的递推式

T ( k ) = { O ( 1 ) , k=0 4 T ( k − 1 ) + O ( 1 ) , k>1 T(k) = \begin{cases} O(1), & \text{k=0} \\ 4T(k-1)+O(1),&\text{k>1} \end{cases} T(k)={O(1),4T(k1)+O(1),k=0k>1

三.程序代码

#include<stdio.h>

int tile=1; 					//L型骨牌序号 
int board[128][128]; 			//二维数组模拟棋盘 

//(tr,tc)表示棋盘的左上角坐标(即确定棋盘位置),size=2^k确定棋盘大小;(tc,dc)表示特殊方块的位置 
void chessBoard(int tr,int tc,int dr,int dc,int size){ 
	//递归出口 
	if(size==1)
		return; 

	//分割棋盘 
	int s=size/2;	
	int t=tile++;		//t记录本层骨牌序号	
	//判断特殊方格在不在左上棋盘 
	if(dr<tr+s&&dc<tc+s){     
		chessBoard(tr,tc,dr,dc,s); 	//特殊方格在左上棋盘的递归处理方法 
	}else{
		board[tr+s-1][tc+s-1]=t;					//不在左上棋盘的话,其特殊方块位于中点(tr+s,tc+s)的左上方 
		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{
		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,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+s,tc+s,dr,dc,s); 
	}else{
		board[tr+s][tc+s]=t;
		chessBoard(tr+s,tc+s,tr+s,tc+s,s); 
	}
} 

int main(){
	chessBoard(0,0,5,5,8);		//(0,0)为顶点,大小为8的棋盘; 特殊方块位于(5,5)
	int i,j;
	printf("\n\n\n");
	for(i=0;i<8;i++){			//输出棋盘内容
		for(j=0;j<8;j++){
			printf("%d\t",board[i][j]);
		}
		printf("\n\n\n");
	}
	return 0;
}
  • 11
    点赞
  • 55
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
以下是用分治策略实现棋盘覆盖问题的完整代码: ``` #include <iostream> #include <cmath> using namespace std; // 定义棋盘大小 const int BOARD_SIZE = 8; // 定义棋盘 int board[BOARD_SIZE][BOARD_SIZE]; // 定义骨牌编号 int tile = 0; // 分治策略实现棋盘覆盖问题 void chessboard(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(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, 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, 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 + s, tc + s, dr, dc, s); } else { board[tr + s][tc + s] = t; chessboard(tr + s, tc + s, tr + s, tc + s, s); } } // 打印棋盘 void printBoard() { for (int i = 0; i < BOARD_SIZE; i++) { for (int j = 0; j < BOARD_SIZE; j++) { cout << board[i][j] << "\t"; } cout << endl; } } int main() { int dr = 0, dc = 0; cout << "请输入特殊方格的行号和列号(0~7): "; cin >> dr >> dc; // 初始化棋盘 for (int i = 0; i < BOARD_SIZE; i++) { for (int j = 0; j < BOARD_SIZE; j++) { board[i][j] = 0; } } // 覆盖棋盘 chessboard(0, 0, dr, dc, BOARD_SIZE); // 打印棋盘 printBoard(); return 0; } ``` 希望能对您有所帮助!

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

萘和

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值