分治算法求解棋盘覆盖问题

1. 问题描述:

在一个2k×2k 个方格组成的棋盘中,恰有一个方格与其它方格不同,称该方格为一特殊方格,且称该棋盘为一特殊棋盘。在棋盘覆盖问题中,要用图示的4种不同形态的L型骨牌覆盖给定的特殊棋盘上除特殊方格以外的所有方格,且任何2个L型骨牌不得重叠覆盖。
在这里插入图片描述

2. 题解:

在这里插入图片描述
划分问题:将 2k∗2k的棋盘划分为 2k−1∗2k−1这样的子棋盘4块。
递归求解:递归填充各个格子,填充分为四个情况,在下面会有解释,递归出口为 k=0也就是子棋盘方格数为1。
递归填充的分为以下四种情况:
(1)如果黑方块在左上子棋盘,则递归填充左上子棋盘;否则填充左上子棋盘的右下角,将右下角看做黑色方块,然后递归填充左上子棋盘。
(2)如果黑方块在右上子棋盘,则递归填充右上子棋盘;否则填充右上子棋盘的左下角,将左下角看做黑色方块,然后递归填充右上子棋盘。
(3)如果黑方块在左下子棋盘,则递归填充左下子棋盘;否则填充左下子棋盘的右上角,将右上角看做黑色方块,然后递归填充左下子棋盘。
(4)如果黑方块在右下子棋盘,则递归填充右下子棋盘;否则填充右下子棋盘的右下角,将左上角看做黑色方块,然后递归填充右下子棋盘。
详细过程如下图所示:
在这里插入图片描述
在这里插入图片描述

// tr,tc分别表示正方形中最左上角的元素位置,dr,dc是黑块的位置,size为边长
void chessBoard(int tr, int tc, int dr, int dc, int size)
{
    
    
    if (size == 1) return;
    int t = tile++, // L型骨牌号
    s = size/2; // 分割棋盘
    // 覆盖左上角子棋盘
    if (dr < tr + s && dc < tc + s)
        // 特殊方格在此棋盘中
        chessBoard(tr, tc, dr, dc, s);
    else {
    
    // 此棋盘中无特殊方格
        // 用 t 号L型骨牌覆盖右下角
        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 {
    
    // 此棋盘中无特殊方格
        / 用 t 号L型骨牌覆盖左下角
        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 {
    
    // 用 t 号L型骨牌覆盖右上角
        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 {
    
    // 用 t 号L型骨牌覆盖左上角
        board[tr + s][tc + s] = t;
        / 覆盖其余方格
        chessBoard(tr+s, tc+s, tr+s, tc+s, s);
    }
}

3. 代码:

参考链接:https://blog.csdn.net/q547550831/article/details/51541527

#include <iostream>

using namespace std;

const int maxNum = 1 << 10;
// 棋盘
int chess[maxNum][maxNum];
// L型牌编号
int number;

void chessBoard(int row, int column, int x, int y, int siz) {
    
    
    // 递归出口
    if(siz == 1) {
    
    
        return;
    }

    // 对半划分成2^(siz - 1) * 2^(siz - 1)的棋盘
    int s = siz / 2;
    // L型牌编号自增
    int t = ++number;
    // 中间点,以此判别(x,y)在哪个子棋盘中
    int centerRow = row + s;
    int centerColumn = column + s;
    // 黑色方格在左上子棋盘
    if(x < centerRow && y < centerColumn) {
    
    
        chessBoard(row, column, x, y, s);
    } else {
    
    
        // 不在则填充左上子棋盘的右下角
        chess[centerRow - 1][centerColumn - 1] = t;
        // 然后覆盖其他格子,注意这时(x,y)要看做已填充位置
        chessBoard(row, column, centerRow - 1, centerColumn - 1, s);
    }

    // 黑色方格在右上子棋盘
    if(x < centerRow && y >= centerColumn) {
    
    
        chessBoard(row, centerColumn, x, y, s);
    } else {
    
    
        // 不在则填充右上子棋盘的左下角
        chess[centerRow - 1][centerColumn] = t;
        // 然后覆盖其他格子,注意这时(x,y)要看做已填充位置
        chessBoard(row, centerColumn, centerRow - 1, centerColumn, s);
    }

    // 黑色方格在左下子棋盘
    if(x >= centerRow && y < centerColumn) {
    
    
        chessBoard(centerRow, column, x, y, s);
    } else {
    
    
        // 不在则填充左下子棋盘的右上角
        chess[centerRow][centerColumn - 1] = t;
        // 然后覆盖其他格子,注意这时(x,y)要看做已填充位置
        chessBoard(centerRow, column, centerRow, centerColumn - 1, s);
    }

    // 黑色方格在右下子棋盘
    if(x >= centerRow && y >= centerColumn) {
    
    
        chessBoard(centerRow, centerColumn, x, y, s);
    } else {
    
    
        // 不在则填充右下子棋盘的左上角
        chess[centerRow][centerColumn] = t;
        // 然后覆盖其他格子,注意这时(x,y)要看做已填充位置
        chessBoard(centerRow, centerColumn, centerRow, centerColumn, s);
    }

}

int main() {
    
    
    // 大小,黑色方格位置
    int siz, x, y;
    while(true) {
    
    
        cout << "(x,y)从(0,0)开始,输入数据为0 0 0即结束程序。" << endl;
        cout << "请输入棋盘大小和黑色方格位置(x,y):";
        cin >> siz >> x >> y;
        // 退出条件
        if(siz == 0) {
    
    
            break;
        }
        // 涂黑(x,y),初始化L型牌编号
        chess[x][y] = number = 1;

        // 分治法填满棋盘
        chessBoard(0, 0, x, y, siz);

        // 输出该棋盘
        for(int i = 0; i < siz; i++) {
    
    
            for(int j = 0; j < siz; j++) {
    
    
                cout << chess[i][j] << "\t";
            }
            cout << endl << endl << endl;
        }
    }

    return 0;
}

猜你喜欢

转载自blog.csdn.net/m0_51339444/article/details/124356805