棋盘覆盖问题-分治法

什么是棋盘覆盖方法?

    我去找其他人的解释,恰恰发现一个矛盾的地方,就是看解释比较难理解,但是看解决棋盘覆盖的过程,就很容易理解什么是棋盘覆盖问题了。所以这里就不解释了,直接给一个解决16*16的棋盘解决过程,看完过程,相信你也理解了什么是棋盘问题了。

    如下:

首先给出一个包含一个奇异点的16*16棋盘:

第一步是将该棋盘分为四个等大的子棋盘:

然后将该棋盘看做是4*4的棋盘,可以看到奇异点在左上角的子棋盘中,那么这一步的任务就是用一个(真的是一个)L型的棋子(下图中红色的格子)将其他三个子棋盘构造成含奇异点的子棋盘:

下一步是将红线分割的子棋盘又切割成四个子棋盘(白色线切开的子棋盘):

然后对每个红色线包围在里面的子棋盘,用一个L型棋子(黄色)又构造出奇异点,使得每个子棋盘都有一个奇异点,即白色线围起来的格子看做是一个整体,里面包含一个黄色的奇异点:

下一步是继续讲白色线包围的格子切分为4个子棋盘,这里为了方便观察,将前面所有的分割线去掉:

同理,对黄色的棋盘构造含奇异点的子棋盘(蓝色):

最后可以分割到2*2的格子,然后每个2*2的子棋盘都已经包含一个奇异点了,剩下的就是用L型旗子去填好剩下的三个格子。

(填充时,最好从左到右)

本文转载自:https://blog.csdn.net/qq_30268545/java/article/details/80600064

附上原创 算法实现代码(java)

public class QiPanFuGai {
    public static void main(String[] args) {
        int xlen = 16;
        int ylen = 16;
        int targetX = 5;
        int targetY = 5;
        int x[][] = new int[xlen][ylen];
        x[targetX][targetY] = 2;
        prinX(x);
        System.out.println();
        f(x,targetX,targetY,xlen,ylen,0,0);
        prinX(x);
    }

    static void f(int [][]x ,int xx,int yy,int xlen,int ylen,int lx,int ly){
        if(xlen<=2){
            return;
        }
        System.out.println("xlen:  "+xlen+"  ylen:   "+ylen);
        System.out.println("lx:  "+lx+"  ly:   "+ly);
        System.out.println("xx:  "+xx+"  yy:   "+yy);
        int mx = lx+(xlen)/2-1;
        int my = ly+(ylen)/2-1;
        int k = 2;
        System.out.println("mx:  "+mx+"  my:   "+my);
        if(xx<=mx){
            //左上
            if(yy<=my){
                System.out.println("左上");
                x[mx+1][my]=k;
                x[mx+1][my+1]=k;
                x[mx][my+1]=k;
                prinX(x);
                System.out.println();
                //当前 奇异点  左上
                f(x,xx,yy,xlen/2,ylen/2,lx,ly);
                //中点下方 奇异点 左下
                f(x,mx+1,my,xlen/2,ylen/2,lx+xlen/2,ly);
                //中点右方 奇异点 右上
                f(x,mx,my+1,xlen/2,ylen/2,lx,ly+ylen/2);
                //中点右下方 奇异点 右下
                f(x,mx+1,my+1,xlen/2,ylen/2,lx+xlen/2,ly+ylen/2);
            }
            //右上
            else {
                System.out.println("右上");
                x[mx][my]=k;
                x[mx+1][my]=k;
                x[mx+1][my+1]=k;
                prinX(x);
                System.out.println();
                //当前 奇异点  右上
                f(x,xx,yy,xlen/2,ylen/2,lx,ly+ylen/2);
                //中点下方 奇异点 左下
                f(x,mx+1,my,xlen/2,ylen/2,lx+xlen/2,ly);
                //中点 奇异点 左上
                f(x,mx,my,xlen/2,ylen/2,lx,ly);
                //中点右下方 奇异点 右下
                f(x,mx+1,my+1,xlen/2,ylen/2,lx+xlen/2,ly+ylen/2);
            }
        }else {
            //左下
            if(yy<=my){
                System.out.println("左下");
                x[mx][my]=k;
                x[mx][my+1]=k;
                x[mx+1][my+1]=k;
                prinX(x);
                System.out.println();
                //当前奇异点 左下
                f(x,xx,yy,xlen/2,ylen/2,lx+xlen/2,ly);
                //中点 奇异点 左上
                f(x,mx,my,xlen/2,ylen/2,lx,ly);
                // 奇异点  右上
                f(x,mx,my+1,xlen/2,ylen/2,lx,ly+ylen/2);
                //中点右下方 奇异点 右下
                f(x,mx+1,my+1,xlen/2,ylen/2,lx+xlen/2,ly+ylen/2);
            }
            //右下
            else {
                System.out.println("");
                x[mx][my]=k;
                x[mx+1][my]=k;
                x[mx][my+1]=k;
                prinX(x);
                System.out.println();
                //当前奇异点 右下
                f(x,xx,yy,xlen/2,ylen/2,lx+xlen/2,ly+ylen/2);
                //中点 奇异点 左上
                f(x,mx,my,xlen/2,ylen/2,lx,ly);
                //奇异点  右上
                f(x,mx,my+1,xlen/2,ylen/2,lx,ly+ylen/2);
                //中点下方 奇异点 左下
                f(x,mx+1,my,xlen/2,ylen/2,lx+xlen/2,ly);
            }
        }

    }

    static void prinX(int x[][]){
        for (int i = 0 ;i<x.length;i++){
            for (int j = 0 ;j<x[0].length;j++){
                System.out.print(x[i][j]+" ");
            }
            System.out.println();
        }
    }
}

输出结果:

0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 
0 2 2 0 0 2 2 0 0 2 2 0 0 2 2 0 
0 2 0 0 0 0 2 0 0 2 0 0 0 0 2 0 
0 0 0 2 2 0 0 0 0 0 0 2 2 0 0 0 
0 0 0 2 0 0 0 0 0 0 0 0 2 0 0 0 
0 2 0 0 0 2 2 0 0 2 2 0 0 0 2 0 
0 2 2 0 0 2 2 0 0 0 2 0 0 2 2 0 
0 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 
0 0 0 0 0 0 0 2 2 0 0 0 0 0 0 0 
0 2 2 0 0 2 0 0 0 0 2 0 0 2 2 0 
0 2 0 0 0 2 2 0 0 2 2 0 0 0 2 0 
0 0 0 2 0 0 0 0 0 0 0 0 2 0 0 0 
0 0 0 2 2 0 0 0 0 0 0 2 2 0 0 0 
0 2 0 0 0 0 2 0 0 2 0 0 0 0 2 0 
0 2 2 0 0 2 2 0 0 2 2 0 0 2 2 0 
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 

 

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
二级残缺棋盘覆盖问题是指在一个大小为2^n x 2^n的棋盘中,去掉其中一个格子后,如何使用L型骨牌(一种覆盖三个方格的L形图案)将剩下的格子完全覆盖,且每个L型骨牌不重叠、不遗漏地覆盖棋盘中的三个方格。 该问题可以使用分治算法解决。具体思路为: 1. 对于当前的残缺棋盘,找到其中任意一个空白格子,并以该空白格子为中心,将整个棋盘分成四个大小相等的子棋盘,其中包含三个L型骨牌覆盖的方案。 2. 在上述四个子棋盘中,选取其中一个仍然是残缺的子棋盘,重复步骤1,直到所有的空白格子都被L型骨牌覆盖。 以下是C语言的分治算法代码实现,其中board数组代表棋盘,size表示当前棋盘大小,x和y表示当前空白格子的坐标。 ``` #include <stdio.h> #define MAXN 1024 int board[MAXN][MAXN]; int cnt = 0; void chessboard(int tr, int tc, int dr, int dc, int size, int x, int y) { if (size == 1) return; // 递归结束条件 int t = ++cnt; int s = size / 2; // 当前空白格子在左上角子棋盘中 if (x < tr + s && y < tc + s) { chessboard(tr, tc, tr + s - 1, tc + s - 1, s, x, y); } else { board[tr + s - 1][tc + s - 1] = t; // 其他三个子棋盘 chessboard(tr, tc, tr + s - 1, tc + s - 1, s, tr + s - 1, tc + s - 1); chessboard(tr, tc + s, tr + s - 1, tc + s, s, tr + s - 1, tc + s); chessboard(tr + s, tc, tr + s, tc + s - 1, s, tr + s, tc + s - 1); chessboard(tr + s, tc + s, dr, dc, s, tr + s, tc + s); } } int main() { int n = 8; // 棋盘大小为2^n x 2^n int x = 6; // 空白格子坐标 int y = 5; board[x][y] = -1; chessboard(0, 0, n-1, n-1, n, x, y); // 分治算法 for (int i=0; i<n; i++) { for (int j=0; j<n; j++) { printf("%3d", board[i][j]); } printf("\n"); } return 0; } ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值