分治法(棋盘覆盖问题)

目录

前言

一、棋盘覆盖

二、图示解析

三、代码实现

四、具体分析

总结


前言

有一个 2^kx2^k (k>0)的棋盘,恰好有一个方格与其他方格不同,称之为特殊方格。现在要用L形骨牌覆盖除了特殊方格以外的其他全部方格,骨牌可以任意旋转,并且任何两个骨牌不能重复。请给出一种覆盖方式

一、棋盘覆盖

(棋盘覆盖问题)在一个2^{k}*2^{k}个方格组成的棋盘上,存在一个特殊的方格,如图棋盘中的红色方格,方格不能被覆盖,要求用四种L型骨牌来覆盖除特殊方格外的整个棋盘,任意两个L型骨牌不能重叠。

二、图示解析

特殊方块左上子棋盘中:                             在右上子棋盘:

        

左下子棋盘中:                                          在右下子棋盘中:

               

三、代码实现

C++:

#include <iostream>   // 包含输入输出流库
using namespace std;  // 使用标准命名空间

#define MAX 1025   // 定义宏MAX为1025
int k;  // 棋盘都大小
int x, y;  // 特殊方格的位置
int board[MAX][MAX];  // 初始化一个大小为MAX*MAX的棋盘数组
int tile = 1;  // 初始瓷砖号为1

void ChessBoard(int tr, int tc, int dr, int dc, int size) {  // 定义一个棋盘分割函数,参数包括起始行列(tr, tc)、特殊方格位置(dr, dc)以及尺寸size
    if (size == 1) return;  // 当尺寸为1时,返回

    int t = tile++;  // 将瓷砖号赋值给t,并递增瓷砖号
    int s = size / 2;  // 棋盘分割尺寸取一半

    if (dr < tr + s && dc < tc + s) {  // 特殊方格在左上子棋盘中
        ChessBoard(tr, tc, dr, dc, s);
    } else {
        board[tr + s - 1][tc + s - 1] = t;  // 记录特殊方格所在位置
        ChessBoard(tr, tc, tr + s - 1, tc + s - 1, s);  // 递归处理左上子棋盘
    }

    if (dr < tr + s && dc >= tc + s) {  // 特殊方格在右上子棋盘中
        ChessBoard(tr, tc + s, dr, dc, s);
    } else {
        board[tr + s - 1][tc + s] = t;
        ChessBoard(tr, tc + s, tr + s - 1, tc + s, s);  // 递归处理右上子棋盘
    }

    if (dr >= tr + s && dc < tc + s) {  // 特殊方格在左下子棋盘中
        ChessBoard(tr + s, tc, dr, dc, s);
    } else {
        board[tr + s][tc + s - 1] = t;
        ChessBoard(tr + s, tc, tr + s, tc + s - 1, s);  // 递归处理左下子棋盘
    }

    if (dr >= tr + s && dc >= tc + s) {  // 特殊方格在右下子棋盘中
        ChessBoard(tr + s, tc + s, dr, dc, s);
    } else {
        board[tr + s][tc + s] = t;
        ChessBoard(tr + s, tc + s, tr + s, tc + s, s);  // 递归处理右下子棋盘
    }
}

int main() {
    k = 3;  // 设置棋盘大小为3
    x = 1, y = 2;  // 特殊方格的位置(x, y)
    int size = 1 << k;  // 计算棋盘总尺寸
    ChessBoard(0, 0, x, y, size);  // 调用棋盘分割函数处理特殊方格
    for (int i = 0; i < size; i++) {
        for (int j = 0; j < size; j++) {
            printf("%4d", board[i][j]);  // 打印棋盘中的数字
        }
        printf("\n");  // 换行
    }
    return 0;  // 返回执行成功
}

四、具体分析

代码模块化分析:

if (dr < tr + s && dc < tc + s) {  // 特殊方格在左上子棋盘中
        ChessBoard(tr, tc, dr, dc, s);
    } else {
        board[tr + s - 1][tc + s - 1] = t;  // 记录特殊方格所在位置
        ChessBoard(tr, tc, tr + s - 1, tc + s - 1, s);  // 递归处理左上子棋盘
    }

1.首先检查特殊方块是否在左上子棋盘中:如果特殊方块的行坐标dr小于起始行坐标tr加上子棋盘尺寸的一半,且列坐标dc小于起始列坐标tc加上子棋盘尺寸的一半,则特殊方块在左上子棋盘中。在这种情况下,递归地调用ChessBoard函数来处理左上子棋盘;否则,将特殊方块放置在左上角子棋盘的中心位置,记录在board数组中,然后递归地处理左上子棋盘的情况。

代码模块化分析:

 if (dr < tr + s && dc >= tc + s) {  // 特殊方格在右上子棋盘中
        ChessBoard(tr, tc + s, dr, dc, s);
    } else {
        board[tr + s - 1][tc + s] = t;
        ChessBoard(tr, tc + s, tr + s - 1, tc + s, s);  // 递归处理右上子棋盘
    }

2.接着检查特殊方块是否在右上子棋盘中:如果特殊方块的行坐标dr小于起始行坐标tr加上子棋盘尺寸的一半,且列坐标dc大于等于起始列坐标tc加上子棋盘尺寸的一半,则特殊方块在右上子棋盘中。在这种情况下,递归地调用ChessBoard函数来处理右上子棋盘;否则,将特殊方块放置在右上角子棋盘的中心位置,记录在board数组中,然后递归地处理右上子棋盘的情况。

代码模块化分析:

if (dr >= tr + s && dc < tc + s) {  // 特殊方格在左下子棋盘中
        ChessBoard(tr + s, tc, dr, dc, s);
    } else {
        board[tr + s][tc + s - 1] = t;
        ChessBoard(tr + s, tc, tr + s, tc + s - 1, s);  // 递归处理左下子棋盘
    }

3.然后检查特殊方块是否在左下子棋盘中:如果特殊方块的行坐标dr大于等于起始行坐标tr加上子棋盘尺寸的一半,且列坐标dc小于起始列坐标tc加上子棋盘尺寸的一半,则特殊方块在左下子棋盘中。在这种情况下,递归地调用ChessBoard函数来处理左下子棋盘;否则,将特殊方块放置在左下角子棋盘的中心位置,记录在board数组中,然后递归地处理左下子棋盘的情况。

代码模块化分析:

if (dr >= tr + s && dc >= tc + s) {  // 特殊方格在右下子棋盘中
        ChessBoard(tr + s, tc + s, dr, dc, s);
    } else {
        board[tr + s][tc + s] = t;
        ChessBoard(tr + s, tc + s, tr + s, tc + s, s);  // 递归处理右下子棋盘
    }

4.最后检查特殊方块是否在右下子棋盘中:如果特殊方块的行坐标dr大于等于起始行坐标tr加上子棋盘尺寸的一半,且列坐标dc大于等于起始列坐标tc加上子棋盘尺寸的一半,则特殊方块在右下子棋盘中。在这种情况下,递归地调用ChessBoard函数来处理右下子棋盘;否则,将特殊方块放置在右下角子棋盘的中心位置,记录在board数组中,然后递归地处理右下子棋盘的情况。


总结

这个算法的好处是它采用了分治策略,将原问题划分为多个子问题进行处理,从而降低了问题规模,简化了问题的复杂度。通过逐步递归处理子棋盘,可以确保特殊方块被正确地放置在整个棋盘上,并且不会覆盖在同一子棋盘内。然而,这个算法的缺点是在处理每个子棋盘时需要进行四次递归调用,这可能会导致递归深度较深,耗费较多的计算资源。此外,递归算法在处理大规模数据时可能会存在栈溢出的风险,需要谨慎处理。

综合而言,这个算法适用于解决特定类型的问题,但需要考虑到递归深度和计算资源的消耗,以确保算法的效率和稳定性。初来乍到,写的不好,欢迎各路大神批评指正!!
 

  • 37
    点赞
  • 27
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值