分治法-棋盘覆盖问题

问题描述:

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

            k=2时的一种棋盘

要求用下图所示的4L形态骨牌覆盖给定的特殊棋盘。

限制条件:

(1)覆盖给定特殊棋盘上除特殊方格以外的所有方格。

(2)任何2L型骨牌不得重叠覆盖。

解决思路:

  • 特殊方格在棋盘中可能出现的位置有4^k种,因而有4^k种不同的棋盘。
  • k>0时,可将2^k×2^k的棋盘划分为4个2^(k-1)×2^(k-1)的子棋盘。
  • 划分后,这4个子棋盘中只有一个子棋盘包含该特殊方格。
  • 将其余3个子棋盘转化为特殊棋盘,转化方式:在三个子棋盘汇合处,设置为特殊方格。
  • 因此,可以用一个L型骨牌覆盖这3个较小棋盘的会合处,从而将原问题转化为4个较小规模的棋盘覆盖问题。
  • 递归地使用这种划分策略,直至将棋盘分割为1×1的子棋盘。

具体步骤:

    1、把整个棋盘划分为左上、右上、左下、右下四块,然后判断特殊的方块在哪一块里面。

    2、假如在左上这一块区域里面,我们就再把这块区域划分四块,直到找到为止。

    3、其他没有特殊方块的区域,开始填充L形的牌。

    4、先把最周围的方格填上L形牌。如下图所示:

5、分割成4块之后,没有特殊方块的那3块区域只要如上图填充完后,中间正好剩下一块L形区域,如下图。

时间复杂度分析:

设T(k)是覆盖一个2k x 2k棋盘所需时间,T(k)满足如下递推式:

解:

具体的实现代码(java实现):


public class ChessProblem {
	
	int size;//容量
	int[][] board;//棋盘
	int specialROW;//特殊点横坐标
	int specialCOL;//特殊点纵坐标
	int number = 0;//L形编号
	
	public ChessProblem(int specialRow, int specialCol, int size) {
		this.size = size;
		this.specialCOL = specialCOL;
		this.specialROW = specialROW;
		board = new int[size][size];
	}
	
	//specialROW   特殊点的行下标
	//specialCOL   特殊点的列下标
	//leftRow      矩阵的左边起点行下标
	//leftCol      矩阵左边起点的列下标
	//size         矩阵的宽或者高
	
 	public void setBoard(int specialROW, int specialCOL, int leftROW, int leftCOL, int size) {
		if (1 == size) {
			return;
		}
		
		int subSize = size / 2;
		number++;
		int n = number;//注意这里一定要吧number存在当前的递归层次里,否则进入下一层递归全局变量会发生改变
		
		//假设特殊点在左上角区域
		if (specialROW < leftROW + subSize && specialCOL < leftCOL + subSize) {
			setBoard(specialROW, specialCOL, leftROW, leftCOL, subSize);
		}
		else {
			//不在左上角,设左上角矩阵的右下角就是特殊点(和别的一起放置L形)
			board[leftROW + subSize - 1][leftCOL + subSize - 1] = n;
			setBoard(leftROW + subSize - 1, leftCOL + subSize - 1, leftROW, leftCOL, subSize);
		}
		
		//假设特殊点在右上方
		if (specialROW < leftROW + subSize && specialCOL >= leftCOL + subSize) {
			setBoard(specialROW, specialCOL, leftROW, leftCOL + subSize, subSize);
		}
		else {
			//不在右上方,设右上方矩阵的左下角就是特殊点(和别的一起放置L形)
			board[leftROW + subSize -1][leftCOL + subSize] = n;
			setBoard(leftROW + subSize -1, leftCOL + subSize, leftROW, leftCOL + subSize, subSize);
		}
		
		//特殊点在左下方
		if (specialROW >= leftROW + subSize && specialCOL < leftCOL + subSize) {
			setBoard(specialROW, specialCOL, leftROW + subSize, leftCOL, subSize);
		}
		else {
			//不在左下方,设左下方矩阵的右上角就是特殊点(和别的一起放置L形)
			board[leftROW + subSize][leftCOL + subSize - 1] = n;
			setBoard(leftROW + subSize, leftCOL + subSize - 1, leftROW + subSize, leftCOL, subSize);
		}
 
		//特殊点在右下角
		if (specialROW >= leftROW + subSize && specialCOL >= leftCOL + subSize) {
			setBoard(specialROW, specialCOL, leftROW + subSize, leftCOL + subSize, subSize);
		}
		else {
			//不在右下角,设右下角矩阵的左上就是特殊点(和别的一起放置L形)
			board[leftROW + subSize][leftCOL + subSize] = n;
			setBoard(leftROW + subSize, leftCOL + subSize, leftROW + subSize, leftCOL + subSize, subSize);			
		}	
	}
	
 	
 	public void printBoard(int specialRow,int specialCol,int size) {
 		setBoard(specialRow, specialCol, 0, 0, size);
 		for (int i = 0; i < board.length; i++) {
			for (int j = 0; j < board.length; j++) {
				System.out.print(board[i][j] + " ");				
			}
			System.out.println();
		}
 	}
 	
 	
	public static void main(String[] args) {
		int N = 4;
		int specialRow = 0;
		int specialCol = 1;
		ChessProblem chessProblem = new ChessProblem(specialRow , specialCol , N);
		chessProblem.printBoard(specialRow, specialCol, N);
	}
}

猜你喜欢

转载自blog.csdn.net/qq_27437197/article/details/85633759