棋盘覆盖问题算法分析与实现(递归)

*昨天上传的代码,经过再次测试发现有问题,其中对边界、终止条件的判断都有错误。。。→_→,今天重新改正,对之前看过代码的童鞋表示sorry。。。(2017.5.13 16:24)*

问题描述:

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

关于棋盘划分的更多概念请戳传送门:棋盘覆盖问题

实现如下:

class Solution
{
public:
    int num = 0;//累计计算
    int **board = NULL;//动态二维数组指针
    void printBoard(int **board, int row, int col)//输出函数
    {
        for (int i = 0; i < row; ++i)
        {
            for (int j = 0; j < col; ++j)
                cout << setw(3) <<board[i][j];
            cout << endl;
        }
        cout << endl;
    }

    void createBoard(int chessboardSize, int dr, int dc)//动态申请内存函数
    {
        board = (int **)malloc(chessboardSize * sizeof(int*));
        assert(board != NULL);
        for (int i = 0; i < chessboardSize; ++i)
        {
            board[i] = (int*)malloc(chessboardSize * sizeof(int));
            assert(board[i] != NULL);
            memset(board[i], 0, sizeof(int)*chessboardSize);
        }
        board[dr][dc] = -1;//将特殊点设置为-1
    }

    void freeBoard(int row)//释放动态内存空间,防止内存泄漏
    {
        for (int i = 0; i < row; ++i)
            free(board[i]);
        free(board);
    }
    //chessboardSize表示此时范围的n*n,n的值
    //dr表示特殊点的行下标
    //dc表示特殊点的列下标
    //tr表示此时范围的左上角在数组中的行下标
    //tc表示此时范围的左上角在数组中的列下标
    void Coverage(int chessboardSize, int dr, int dc, int tr, int tc)
    {
        if (chessboardSize == 1) return;//当范围为1时,表示只有一个元素,return
        int tmp = ++num;//每进入一个范围内,num累加
        int s = chessboardSize / 2;//获取此时范围内的下一个小范围的n大小
        //判断特殊点是否在范围内的第一象限
        if (dr < tr + s && dr >= 0 && dc < tc + s && dc >= 0)
                    Coverage(s, dr, dc, tr, tc);
        else//否则,将此第一象限的右下角设置为相对特殊点
        {
            board[tr + s - 1][tc + s - 1] = tmp;
            Coverage(s, tr + s - 1, tc + s - 1, tr, tc);
        }
        //判断特殊点是否在范围内的第四象限
        if (dr >= 0 && dr < tr + s && dc >= tc + s && dc < tc + 2 * s)
            Coverage(s, dr, dc, tr, tc + s);
        else//否则,将此第四象限的右下角设置为相对特殊点
        {
            board[tr + s - 1][tc + s] = tmp;
            Coverage(s, tr + s - 1, tc + s, tr, tc + s);
        }
        //判断特殊点是否在范围内的第二象限
        if (dr >= tr + s && dr < tr + 2 * s && dc >= 0 && dc < tc + s)
            Coverage(s, dr, dc, tr + s, tc);
        else//否则,将此第二象限的右下角设置为相对特殊点
        {
            board[tr + s][tc + s - 1] = tmp;
            Coverage(s, tr + s, tc + s - 1, tr + s, tc);
        }
        //判断特殊点是否在范围内的第三象限
        if (dr >= tr + s && dr < tr + 2 * s && dc >= tc + s && dc < tc + 2 * s)
            Coverage(s, dr, dc, tr + s, tc + s);
        else//否则,将此第三象限的右下角设置为相对特殊点
        {
            board[tr + s][tc + s] = tmp;
            Coverage(s, tr + s, tc + s, tr + s, tc + s);
        }
        //printBoard(board, 8, 8);
    }

    void ChessboardCoverage(int chessboardSize, int dr, int dc)
    {
        if (chessboardSize < 1 || dr < 0 || dc < 0 || dr >= chessboardSize || dc >= chessboardSize) return;//防御性动作
        createBoard(chessboardSize, dr, dc);//动态生成二维数组
        Coverage(chessboardSize, dr, dc, 0, 0);//开始覆盖
        printBoard(board, chessboardSize, chessboardSize);//输出
        freeBoard(chessboardSize);//释放动态空间
    }
};

测试用例:
棋盘覆盖算法

  • 1
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
棋盘覆盖问题是指在一个大小为2^n * 2^n的棋盘上,恰好有一个方格是特殊的,现在要用L型骨牌覆盖整个棋盘,求覆盖方案。这个问题可以使用分治算法来解决,具体步骤如下: 1.将整个棋盘分成四个大小相等的子棋盘,其中特殊方格在其中一个子棋盘中。 2.对于不包含特殊方格的三个子棋盘,使用递归的方式继续进行分治。 3.对于包含特殊方格的那个子棋盘,将其分成四个子棋盘,其中特殊方格在其中一个子棋盘中,然后对于不包含特殊方格的三个子棋盘,使用递归的方式继续进行分治。 4.重复上述步骤,直到棋盘被完全覆盖。 下面是一个Python实现的例子: ```python def chessboard_cover(board, tr, tc, dr, dc, size): global tile if size == 1: return t = tile tile += 1 s = size // 2 # 1 if dr < tr + s and dc < tc + s: chessboard_cover(board, tr, tc, dr, dc, s) else: board[tr + s - 1][tc + s - 1] = t chessboard_cover(board, tr, tc, tr + s - 1, tc + s - 1, s) # 2 if dr < tr + s and dc >= tc + s: chessboard_cover(board, tr, tc + s, dr, dc, s) else: board[tr + s - 1][tc + s] = t chessboard_cover(board, tr, tc + s, tr + s - 1, tc + s, s) # 3 if dr >= tr + s and dc < tc + s: chessboard_cover(board, tr + s, tc, dr, dc, s) else: board[tr + s][tc + s - 1] = t chessboard_cover(board, tr + s, tc, tr + s, tc + s - 1, s) # 4 if dr >= tr + s and dc >= tc + s: chessboard_cover(board, tr + s, tc + s, dr, dc, s) else: board[tr + s][tc + s] = t chessboard_cover(board, tr + s, tc + s, tr + s, tc + s, s) # 测试 size = 8 board = [[0 for j in range(size)] for i in range(size)] tile = 1 chessboard_cover(board, 0, 0, 0, 1, size) for i in range(size): for j in range(size): print(str(board[i][j]).center(4), end='') print() ```

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值