分治回溯算法----棋盘覆盖问题

本文探讨了如何利用分治回溯算法解决棋盘覆盖问题。在2^k×2^k的棋盘中,有一个特殊方格,目标是使用4种不同形状的L型骨牌覆盖所有非特殊方格,不允许骨牌重叠。文章通过4*4棋盘的例子展示了解决方案,并给出了棋盘填充的实现过程。

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

四种不同形状的L型骨牌:

骨牌覆盖的结果:

棋盘填充的实现:

//分治回溯 分治的应用 之 棋盘覆盖问题
/*
利用分治算法 将棋盘分成三个子棋盘
首先要先判断特殊方格在哪个子棋盘中
若特殊方格在左上子棋盘中 就继续向下递归 将子棋盘再分为四个子棋盘即可
若左上子棋盘中没有特殊方格 我们就将左上子棋盘中的右下方的格子 当成一个特殊方格
再继续向下递归 将子棋盘再分为四个子棋盘 直到棋盘被全部覆为止
若右上子棋盘中没有特殊方格 我们就将右上子棋盘中的左下方的格子 当成一个特殊方格
再继续向下递归 将子棋盘再分为四个子棋盘 直到棋盘被全部覆为止
若左下子棋盘中没有特殊方格 我们就将下上子棋盘中的右上方的格子 当成一个特殊方格
再继续向下递归 将子棋盘再分为四个子棋盘 直到棋盘被全部覆为止
若右下子棋盘中没有特殊方格 我们就将右下子棋盘中的左上方的格子 当成一个特殊方格
再继续向下递归 将子棋盘再分为四个子棋盘 直到棋盘被全部覆为止
 */
public class ChessboardCoverage {
    //表示棋盘尺寸
    private static int BOARD_SIZE = 8;
    //表示棋盘
    private static int[][] chess = new int[BOARD_SIZE][BOARD_SIZE];
    //骨牌编号 一层L型骨牌的编号要一直 0表示特殊方格
    private static int title = 0;

    public static void main(String[] args) {
        Scanner input = new Scanner(System.in);
        System.out.println("请输入特殊格子在棋盘中的坐标:");
        int dr = input.nextInt(); //表示特殊格子在棋盘中的横坐标
        int dc = input.nextInt(); //表示特殊格子在棋盘中的纵坐标

        chessBoard(0, 0, dr, dc, BOARD_SIZE); //棋盘填充方法

        for(int i = 0; i < chess.length; i++){ //遍历输出棋盘
            for(int j = 0; j < chess.length; j++){
                System.out.print(chess[i][j] + "\t");
            }
            System.out.println();
        }
    }

    //棋盘填充方法
    //(tr, tc)表示棋盘或者子棋盘的对应起点坐标 (dr, dc)表示棋盘中特殊坐标的位置 size表示棋盘或子棋盘尺寸
    private static void chessBoard(int tr, int tc, int dr, int dc, int size) {
        if(size == 1){ //递归临界条件 当棋盘尺寸等于1时 返回
            return;
        }
        int s = size / 2; //表示棋盘或子棋盘尺寸 每次递归就除2 如将8*8的棋盘 分成四个4*4的子棋盘
        int num = ++title; //更新L型骨牌编号 同一层的骨牌编号应该一致

        //判断特殊坐标 在棋盘中的哪一部分子棋盘中
        //如果特殊方格在左上子棋盘中
        if(dr < tr + s && dc < tc + s){
            chessBoard(tr, tc, dr, dc, s); //向下递归chessBoard方法 更新子方格起始位置和特殊方格位置
        }else{ //如果特殊方格不在左上子棋盘中
            chess[tr + s - 1][tc + s - 1] = num; //就规定左上角子棋盘中的右下角方格为特殊方格 将编号写入特殊方格
            chessBoard(tr, tc, tr + s - 1, tc + s - 1, s);//向下递归chessBoard方法 更新子方格起始位置和特殊方格位置
        }

        //如果特殊方格在右上子棋盘
        if(dr >= tr + s && dc < tc + s) {
            chessBoard(tr + s, tc, dr, dc, s); //向下递归chessBoard方法 更新子方格起始位置和特殊方格位置
        }else{ //如果特殊方格不在右上子棋盘中
            chess[tr + s][tc + s - 1] = num; //就规定右上角子棋盘中的左下角方格为特殊方格 将编号写入特殊方格
            chessBoard(tr + s, tc, tr + s,tc + s - 1, s); //向下递归chessBoard方法 更新子方格起始位置和特殊方格位置
        }

        //如果特殊方格在左下子棋盘
        if(dr < tr + s && dc >= tc + s){
            chessBoard(tr, tc + s, dr, dc, s); //向下递归chessBoard方法 更新子方格起始位置和特殊方格位置
        }else{ //如果特殊方格不在左下子棋盘中
            chess[tr + s - 1][tc + s] = num; //就规定左下角子棋盘中的右上角方格为特殊方格 将编号写入特殊方格
            chessBoard(tr, tc + s, tr + s - 1, tc + s, s); //向下递归chessBoard方法 更新子方格起始位置和特殊方格位置
        }

        //如果特殊方格在右下子棋盘
        if(dr >= tr + s && dc >=tc + s){
            chessBoard(tr + s, tc + s, dr, dc, s); //向下递归chessBoard方法 更新子方格起始位置和特殊方格位置
        }else{  //如果特殊方格不在右下子棋盘中
            chess[tr + s][tc + s] = num; //就规定右下角子棋盘中的左上角方格为特殊方格 将编号写入特殊方格
            chessBoard(tr + s, tc + s, tr + s, tc + s, s); //向下递归chessBoard方法 更新子方格起始位置和特殊方格位置
        }
    }
}

 

棋盘填充的结果为:

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值