棋盘覆盖问题(分治)

问题描述:在一个 2 k ∗ 2 k ( k > 0 ) 2^k*2^k(k>0) 2k2k(k>0)的棋盘,只有一个与其它方格不同的特殊方格,现在要用下图所示的 L 形骨牌覆盖除了特殊方格外的其它全部方格,任意两骨牌不能重叠,给出一种覆盖方法。
在这里插入图片描述

本题可以将大棋盘划分为四个大小相同的象限,那么这个特殊方格必定存在其中一个象限,根据方格存在的不同象限,L 形骨牌的摆法:
在这里插入图片描述
这样便能使被划分的四个象限均存在一个“特殊的方格”,达到分治的条件。

分治一个最重要的特点在于一个复杂的大问题可以分解为几个性质或求解思路相同的小问题,且小问题更容易求解。

代码实现过程中需要创建一个和初始棋盘大小相同的二维数组用来保存棋盘每个方格覆盖骨牌的编号。

java代码

public class Solution {
	int tile; 												// 骨牌编号,从1开始
	int[][] board; 											// 与初始棋盘对应的二维数组

	public Solution(int size) { 							// 构造函数,初始化
		board = new int[size][size];
		tile = 1;
	}

	// (tr,tc)表示一个象限左上角方格的行列号,(dr,dc)表示特殊方格行列号,其中初始棋盘左上角行列号(0,0)
	public void chessBoard(int tr, int tc, int dr, int dc, int size) {
		if (size == 1) { 									// 递归出口
			return;
		}
		
		int t = tile++; 									// 取骨牌
		int s = size >> 1; 									// 分割棋盘
		// 考虑左上角象限
		if (dr < tr + s && dc < tc + s) { 					// 特殊方格在此象限处理此象限
			chessBoard(tr, tc, dr, dc, s);
		} else { 													// 特殊方格不在此象限
			board[tr + s - 1][tc + s - 1] = t; 						// 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; 							// 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; 							// 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; 								// t号骨牌覆盖象限最左上角
			chessBoard(tr + s, tc + s, tr + s, tc + s, s); 			// 将左上角视为特殊方格继续处理该象限
		}
	}

	public static void main(String[] args) {
		int k = 3;
		int size = 1 << k;
		Solution s = new Solution(size);
		int tr = 1;											// 特殊方格的行号
		int tc = 2;											// 特殊方格的列号
		s.board[tr][tc] = 0; 								// 特殊方格用0表示
		s.chessBoard(0, 0, tr, tc, size);
		// 打印覆盖结果
		for (int i = 0; i < size; i++) {
			for (int j = 0; j < size; j++) {
				System.out.print(s.board[i][j] + "\t");
			}
			System.out.println();
		}
	}	
}

运行结果(0表示特殊方格的位置,3个相同数字代表一块骨牌)
在这里插入图片描述

时间复杂度分析

T ( k ) T(k) T(k)表示求解一个 2 k ∗ 2 k 2^k*2^k 2k2k棋盘的时间

  • k = 1 k=1 k=1 T ( k ) = O ( 1 ) T(k)=Ο(1) T(k)=O(1)
  • k > 1 k>1 k>1 T ( k ) = 4 T ( k − 1 ) T(k)=4T(k-1) T(k)=4T(k1)

∴ T ( k ) = O ( 4 k ) \therefore T(k)=Ο(4^k) T(k)=O(4k)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值