棋盘覆盖问题


拒绝白嫖,白嫖有罪,点个赞再走呗

问题描述

在一个由2^k * 2^k个方格组成的棋盘中,若恰有一个方格与其他方格不同,称该方格为特殊方格,且称该棋盘为特殊棋盘。显然,特殊方格在棋盘中出现的位置有 4^k种不同的棋盘。我们要用3个方格组成的L型的方块将整个棋盘覆盖掉。

思路

首先,我们先考虑22的棋盘,无论特殊方格在哪,另外三个就是一个L型的方块,刚好将整个格棋盘覆盖掉。接下来我们考虑44的棋盘,我们首先将其分为四个22的棋盘,特殊方格必定在其中一个棋盘中,则这个棋盘就是22的棋盘的解决方案,另外三个棋盘,我们各取一个角当做一个L型,剩下的,我想你们也都会了。如下图
在这里插入图片描述最终变成了在这里插入图片描述

同理88的棋盘的时候,我们首先将棋盘分为4个4**4的棋盘,其中一个棋盘就是上述44棋盘的解法,另外3个我们继续去一个角,组成L型的方块。如下图
在这里插入图片描述然后将每一个4*4的方格都解出来就可以了在这里插入图片描述

实现

我们首先就是要构造棋盘,我们用的是二维数组来代替棋盘,我们用同一种数字代表L型的方块

打印整个棋盘

public void Println(int a[][]){
        for (int i=0;i<a.length;i++){
            for (int j=0;j<a[i].length;j++){
                System.out.printf("%d\t",a[i][j]);
            }
            System.out.println("");
        }
    }

基本的算法

    public void ChessBoard(int tr,int tc,int dr,int dc,int size) {//dc:列,dr:行,为特殊方格的位置
        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 {
            a[tr + s - 1][tc + s - 1] = t;
            ChessBoard(tr, tc, tr + s - 1, tc + s - 1, s);
        }
        if (dc >= tc + s && dr < tr + s) {//特殊方格在右上角
            ChessBoard(tr, tc + s, dr, dc, s);
        } else {
            a[tr + s - 1][tc + s] = t;
            ChessBoard(tr, tc + s, tr + s - 1, tc + s, s);
        }
        if (dc < tc + s && dr >= tr + s) {//特殊方格在左下角
            ChessBoard(tr + s, tc, dr, dc, s);
        } else {
            a[tr + s][tc + s - 1] = t;
            ChessBoard(tr + s, tc, tr + s, tc + s - 1, s);
        }
        if (dc >= tc + s && dr >= tr + s) {//特殊方格在右下角
            ChessBoard(tr + s, tc + s, dr, dc, s);
        } else {
            a[tr + s][tc + s] = t;
            ChessBoard(tr + s, tc + s, tr + s, tc + s, s);
        }
    }

测试

public static void main(String[] args) {
        Scanner in = new Scanner(System.in);
        int n,i,j;
        System.out.println("请输入方格为多大,和特殊方格的坐标,例如16 2 3");
        n = in.nextInt();
        i = in.nextInt();
        j = in.nextInt();
        Main yyp = new Main();
        yyp.a = new int[n][n];
        yyp.ChessBoard(0,0,i-1,j-1,n);
        yyp.Println(yyp.a);
    }

全部代码

package suanfa.cover;

import java.util.Scanner;

public class Main {

    int a[][];
    private int tile = 1;

    public void ChessBoard(int tr,int tc,int dr,int dc,int size) {//dc:列,dr:行,为特殊方格的位置
        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 {
            a[tr + s - 1][tc + s - 1] = t;
            ChessBoard(tr, tc, tr + s - 1, tc + s - 1, s);
        }
        if (dc >= tc + s && dr < tr + s) {//特殊方格在右上角
            ChessBoard(tr, tc + s, dr, dc, s);
        } else {
            a[tr + s - 1][tc + s] = t;
            ChessBoard(tr, tc + s, tr + s - 1, tc + s, s);
        }
        if (dc < tc + s && dr >= tr + s) {//特殊方格在左下角
            ChessBoard(tr + s, tc, dr, dc, s);
        } else {
            a[tr + s][tc + s - 1] = t;
            ChessBoard(tr + s, tc, tr + s, tc + s - 1, s);
        }
        if (dc >= tc + s && dr >= tr + s) {//特殊方格在右下角
            ChessBoard(tr + s, tc + s, dr, dc, s);
        } else {
            a[tr + s][tc + s] = t;
            ChessBoard(tr + s, tc + s, tr + s, tc + s, s);
        }
    }

    public void Println(int a[][]){
        for (int i=0;i<a.length;i++){
            for (int j=0;j<a[i].length;j++){
                System.out.printf("%d\t",a[i][j]);
            }
            System.out.println("");
        }
    }

    public static void main(String[] args) {
        Scanner in = new Scanner(System.in);
        int n,i,j;
        System.out.println("请输入方格为多大,和特殊方格的坐标,例如16 2 3");
        n = in.nextInt();
        i = in.nextInt();
        j = in.nextInt();
        Main yyp = new Main();
        yyp.a = new int[n][n];
        yyp.ChessBoard(0,0,i-1,j-1,n);
        yyp.Println(yyp.a);
    }

}

结果

在这里插入图片描述

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值