残缺棋盘问题

残缺棋盘是一个 2 k ∗ 2 k 2^k * 2^k 2k2k(k >= 1)个方格的棋盘,其中恰有1个方格残缺。图中给出k = 1时各种可能的残缺棋盘,其中残缺部分用阴影表示。
例题
思路:不停地分割寻找残缺块所在区域,然后在残缺块周围填充第一块(这个时候size=2);然后回溯一层,填充伪残缺块(这个时候size=4);然后对当前size=4的另外三个子棋盘依次填充(含残缺块的子棋盘当然不再填充了)。
填充完size=4的棋盘后,回溯到size=8的棋盘,重复刚才的过程:先填充size=8这个棋盘的伪残缺块,然后填充另外的三个子棋盘……
图示

public class School05 {
    public static int count = 0;//标号1到(boardSize^2-1)/3

    public static void main(String[] args) {
        int boardSize = 8;
        int[][] board = new int[boardSize][boardSize];//表示棋盘
        cover(board, 0, 0, boardSize, 0, 0);//对原始棋盘进行覆盖
        for (int i = 0; i < boardSize; i++) {//输出结果
            for (int j = 0; j < boardSize; j++) {
                System.out.print(board[i][j] + " ");
            }
            System.out.println();
        }
    }

    //覆盖以(tr, tc)为左上角坐标,宽为size的棋盘。残缺块或伪残缺块的坐标为(dr, dc)
    public static void cover(int[][] board, int tr, int tc, int size, int dr, int dc) {
        if (size < 2) { //假如棋盘分割到不足2*2则直接返回(这时候没办法用模板去覆盖棋盘了)
            return;
        }
        int s = size / 2; //表示即将被再次分割后的棋盘大小
        if (dr < (tr + s) && dc < (tc + s)) { //表示对当前输入的棋盘而言,残缺块在左上角部分的子棋盘
            cover(board, tr, tc, s, dr, dc); //对左上角子棋盘分割
            count++;
            board[tr + s - 1][tc + s] = count; //下面三个赋值语句是用(1)号模板覆盖
            board[tr + s][tc + s - 1] = count;
            board[tr + s][tc + s] = count;
            cover(board, tr, tc + s, s, tr + s - 1, tc + s); //对右上角子棋盘分割
            cover(board, tr + s, tc, s, tr + s, tc + s - 1); //对左下角子棋盘分割
            cover(board, tr + s, tc + s, s, tr + s, tc + s); //对右下角子棋盘分割
        } else if (dr < (tr + s) && dc >= (tc + s)) { //表示对当前输入的棋盘而言,残缺块在右上角部分的子棋盘
            cover(board, tr, tc + s, s, dr, dc); //对右上角子棋盘分割
            count++;
            board[tr + s - 1][tc + s - 1] = count; //下面三个赋值语句是用(2)号模板覆盖
            board[tr + s][tc + s - 1] = count;
            board[tr + s][tc + s] = count;
            cover(board, tr, tc, s, tr + s - 1, tc + s - 1); //对左上角子棋盘分割
            cover(board, tr + s, tc, s, tr + s, tc + s - 1); //对左下角子棋盘分割
            cover(board, tr + s, tc + s, s, tr + s, tc + s); //对右下角子棋盘分割
        } else if (dr >= (tr + s) && dc < (tc + s)) { //表示对当前输入的棋盘而言,残缺块在左下角部分的子棋盘
            cover(board, tr + s, tc, s, dr, dc);
            count++;
            board[tr + s - 1][tc + s - 1] = count; //下面三个赋值语句是用(3)号模板覆盖
            board[tr + s - 1][tc + s] = count;
            board[tr + s][tc + s] = count;
            cover(board, tr, tc, s, tr + s - 1, tc + s - 1);
            cover(board, tr, tc + s, s, tr + s - 1, tc + s);
            cover(board, tr + s, tc + s, s, tr + s, tc + s);
        } else if (dr >= (tr + s) && dc >= (tc + s)) { //表示对当前输入的棋盘而言,残缺块在右下角部分的子棋盘
            cover(board, tr + s, tc + s, s, dr, dc);
            count++;
            board[tr + s - 1][tc + s - 1] = count; //下面三个赋值语句是用(4)号模板覆盖
            board[tr + s - 1][tc + s] = count;
            board[tr + s][tc + s - 1] = count;
            cover(board, tr, tc, s, tr + s - 1, tc + s - 1);
            cover(board, tr, tc + s, s, tr + s - 1, tc + s);
            cover(board, tr + s, tc, s, tr + s, tc + s - 1);
        }
    }
}
/*注:下面都是为了写代码的时候容易写出来而假定取某一固定的值,只是为了比较好写代码。
实际情况比如s等于1的时候,会发现tr+s-1会等于tr,但不能把tr+s-1替换成tr,因为s可能会有好多值,当s等于2的时候就会出现错误。*/
        if (dr < (tr + s) && dc < (tc + s)) { //残缺块在左上角部分的子棋盘
            cover(board, tr, tc, s, dr, dc); //对左上角子棋盘分割
            count++;
            //在写代码时,可以把下面的s当成是1,这样比较容易写出代码。因为程序执行到最后size是2,s就是1
            board[tr + s - 1][tc + s] = count;
            board[tr + s][tc + s - 1] = count;
            board[tr + s][tc + s] = count;
            //在写代码时,可以把下面的s当成是2,这样比较容易写出代码。
            /*因为当上面s等于1的代码执行完之后执行下面三个递归时,会将s等于1传递给size,
            size小于2时程序会直接返回,此时整个程序会回溯到s等于2的情况*/
            cover(board, tr, tc + s, s, tr + s - 1, tc + s); //对右上角子棋盘分割
            cover(board, tr + s, tc, s, tr + s, tc + s - 1); //对左下角子棋盘分割
            cover(board, tr + s, tc + s, s, tr + s, tc + s); //对右下角子棋盘分割
        } 
  • 3
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

静波波呀

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值