棋盘覆盖(java实现)

棋盘覆盖

问题描述

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

在这里插入图片描述

2.思路

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-3SArL3be-1633588103361)(C:\Users\Big ant\AppData\Roaming\Typora\typora-user-images\image-20211007121902387.png)]

1.当k>0时,将2k*2k棋盘分割为4个2(k-1)*2(k-1)子棋盘

2.将这三个无特殊方格的子棋盘转换为特殊棋盘,用一个L型骨盘覆盖这三个较小棋盘的会和处

3.递归地使用这种分割方法,直至棋盘简化为1*1棋盘,就结束递归。

3.注意

1.每次都对分割后的四个小棋盘进行判断,判断特殊方格是否在里面。

这里的判断的方法是每次先记录下整个大棋盘的左上角方格的行列坐标,然后再与特殊方格坐标进行比较,就可以知道特殊方格是否在该块棋盘中。

  1. 如果特殊方块在里面,这直接递归下去求即可,
  2. 如果不在,这根据分割的四个棋盘的不同位置,把右下角、左下角、右上角或者左上角的方格标记为特殊方块,然后继续递归。在递归函数里,还要有一个变量s来记录边的方格数,每次对棋盘进行划分时,边的方格数都会减半,这个变量是为了方便判断特殊方格的位置。

左上角方格的行列坐标是确定的,根据棋盘的大小和要判断在哪个区域确定

实现细节:

用4*4的棋盘举例

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-d2JG4qJ3-1633588103363)(C:\Users\Big ant\AppData\Roaming\Typora\typora-user-images\image-20211007124027712.png)]

要判断特殊的方格在哪一个区域:

根据传入的参数size,leftRow,leftCol可以将棋盘划分为四个区域,然后和特殊点比较

1. 左上角:`specialRow < leftRow+size && specialCol < leftCol+size`
2. 右上角:`specialRow < leftRow+size && specialCol >= leftCol+size`
3. 左下角:`specialRow >= leftRow+size && specialCol < leftCol+size`
4. 右下角:`specialRow >= leftRow+size && specialCol >= leftCol+size`

填充的特殊点也可以用这几个参数来确定

​ 如果特殊点不在左上角,填充的特殊点在该区域的右下角leftRow+size-1,leftRol+size-1

​ 如果特殊点不在右上角,填充的特殊点在该区域的左下角leftRow+size-1,leftRol+size

​ 如果特殊点不在左下角,填充的特殊点在该区域的右上角leftRow+size,leftCol+size-1

​ 如果特殊点不在右下角,填充的特殊点在该区域的左下角leftRow+size,leftCol+size

2.递归的结束条件

  1. size为1时
//大小为1时,结束递归
if (1 == size) {
    return;
}
  1. size为2时
//大小为2时,结束递归
if(size == 2){
    number++;
    if(specialCol != leftCol || specialRow != leftRow)
        board[leftRow][leftCol] = number;
    if(specialCol != leftCol+1 || specialRow != leftRow+1)
        board[leftRow+1][leftCol+1] = number;
    if(specialCol != leftCol+1 || specialRow != leftRow)
        board[leftRow][leftCol+1] = number;
    if(specialCol != leftCol || specialRow != leftRow+1)
        board[leftRow+1][leftCol] = number;
    return;
}

4.代码

package com.java.test;

public class ChessProblem {

    int size;//容量
    int[][] board;//棋盘
    int specialRow;//特殊点横坐标
    static int number = 0;//L形编号,这个一定要是静态的,可以在任何地方访问到
    int specialCol;//特殊点纵坐标

    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) {
        //大小为1时,结束递归
        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] + "\t");
            }
            System.out.println();
        }
    }


    public static void main(String[] args) {
        //棋盘的大小
        int N = 8;
        //特殊点的坐标
        int specialRow = 0;
        int specialCol = 1;
        ChessProblem chessProblem = new ChessProblem(specialRow , specialCol , N);
        chessProblem.printBoard(specialRow, specialCol, N);
    }

}

5.运行截图

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ydFDm3Vy-1633588103365)(C:\Users\Big ant\AppData\Roaming\Typora\typora-user-images\image-20211007140756176.png)]

posted @ 2022-11-10 11:05  老羊肖恩  阅读(97)  评论(0编辑  收藏  举报