JAVA算法:棋盘覆盖算法(经典算法问题)

JAVA算法:棋盘覆盖算法(经典算法问题)

经典算法问题:在一个2^k×2^k (k≥0)个方格组成的棋盘中,恰有一个方格与其他方格不同,称该方格为特殊方格。显然,特殊方格在棋盘中可能出现的位置有4^k种,因而有4^k种不同的棋盘,下图(1)所示是k=2时16种棋盘中的一个。棋盘覆盖问题(chess cover problem)要求用图(2)所示的4种不同形状的L型骨牌覆盖给定棋盘上除特殊方格以外的所有方格,且任何2个L型骨牌不得重叠覆盖。

图(1)

       
       
       
       

图(2)

JAVA算法:棋盘覆盖算法(经典算法问题)_第1张图片

 

如何应用分治法求解棋盘覆盖问题呢?

分治的技巧在于如何划分棋盘,使划分后的子棋盘的大小相同,并且每个子棋盘均包含一个特殊方格,从而将原问题分解为规模较小的棋盘覆盖问题。k>0时,可将2^k×2^k的棋盘划分为4个2^(k-1)×2^(k-1)的子棋盘,如图4.11(a)所示。这样划分后,由于原棋盘只有一个特殊方格,所以,这4个子棋盘中只有一个子棋盘包含该特殊方格,其余3个子棋盘中没有特殊方格。为了将这3个没有特殊方格的子棋盘转化为特殊棋盘,以便采用递归方法求解,可以用一个L型骨牌覆盖这3个较小棋盘的会合处,如图4.11(b)所示,从而将原问题转化为4个较小规模的棋盘覆盖问题。递归地使用这种划分策略,直至将棋盘分割为1×1的子棋盘。

JAVA算法:棋盘覆盖算法(经典算法问题)_第2张图片 


算法设计

package com.bean.algorithm.basic;

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);
	}

}

程序运行结果

2 0 3 3 
2 2 1 3 
4 1 1 5 
4 4 5 5 

 

你可能感兴趣的:(算法分析与设计,JAVA算法学习)