分治法——棋盘覆盖问题

原创 2016年05月30日 21:59:58

分治法——棋盘覆盖问题

棋盘覆盖问题。有一个2k2k的方格棋盘,恰有一个方格是黑色的,其他为白色。你的任务是用包含3个方格的L型牌覆盖所有白色方格。黑色方格不能被覆盖,且任意一个白色方格不能同时被两个或更多牌覆盖。如图所示为L型牌的4种旋转方式。
L型牌

分治三步骤
划分问题:将2k2k的棋盘划分为2k12k1这样的子棋盘4块。
递归求解:递归填充各个格子,填充分为四个情况,在下面会有解释,递归出口为k=0也就是子棋盘方格数为1。
合并问题:不需要合并子问题。
递归填充的四种情况
如果黑方块在左上子棋盘,则递归填充左上子棋盘;否则填充左上子棋盘的右下角,将右下角看做黑色方块,然后递归填充左上子棋盘。
如果黑方块在右上子棋盘,则递归填充右上子棋盘;否则填充右上子棋盘的左下角,将左下角看做黑色方块,然后递归填充右上子棋盘。
如果黑方块在左下子棋盘,则递归填充左下子棋盘;否则填充左下子棋盘的右上角,将右上角看做黑色方块,然后递归填充左下子棋盘。
如果黑方块在右下子棋盘,则递归填充右下子棋盘;否则填充右下子棋盘的右下角,将左上角看做黑色方块,然后递归填充右下子棋盘。

棋盘覆盖问题的递归解法

棋盘覆盖问题分治算法

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);
    }

}

测试主程序

#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;
}

输出数据

(x,y)从(0,0)开始,输入数据为0 0 0即结束程序。
请输入棋盘大小和黑色方格位置(x,y):2 0 0
1       2


2       2


(x,y)从(0,0)开始,输入数据为0 0 0即结束程序。
请输入棋盘大小和黑色方格位置(x,y):4 1 1
3       3       4       4


3       1       2       4


5       2       2       6


5       5       6       6


(x,y)从(0,0)开始,输入数据为0 0 0即结束程序。
请输入棋盘大小和黑色方格位置(x,y):8 2 2
4       4       5       5       9       9       10      10


4       3       3       5       9       8       8       10


6       3       1       7       11      11      8       12


6       6       7       7       2       11      12      12


14      14      15      2       2       19      20      20


14      13      15      15      19      19      18      20


16      13      13      17      21      18      18      22


16      16      17      17      21      21      22      22



(x,y)从(0,0)开始,输入数据为0 0 0即结束程序。
请输入棋盘大小和黑色方格位置(x,y):0 0 0

Process returned 0 (0x0)   execution time : 29.988 s
Press any key to continue.
版权声明:如需转载,请联系本人获取许可且必须注明出处,详见联系方式。

相关文章推荐

棋盘覆盖问题

//棋盘覆盖问题 /* (tr,tc)是棋盘左上角的方格坐标 (dr,dc)是特殊方格所在的坐标 size是棋盘的行数和列数 */ #include using namespace std; in...
  • acm_JL
  • acm_JL
  • 2016年03月20日 20:34
  • 3795

棋盘覆盖问题的递归解决

搭建博客第一次就写一下,自己在github上利用github page这个功能搭建博客的过程也算是一个教程吧。第一次写有什么不对的地方请大家指正啦。准备工作首先想要使用github page搭建一个博...

棋盘覆盖问题

在一个 2^k * 2^k 个方格组成的棋盘中,若恰有一个方格与其它方格不同,则称该方格为一特殊方格,称该棋盘为一特殊棋盘。显然特殊方格在棋盘上出现的位置有 4^k 种情形。因而对任何 k>=0 ,有...
  • akof1314
  • akof1314
  • 2010年03月27日 23:10
  • 16044

[分治,递归]棋盘覆盖问题

问题描述 在一个2^k×2^k 个方格组成的棋盘中,恰有一个方格与其他方格不同,称该方格为一特殊方格,且称该棋盘为一特殊棋盘。在棋盘覆盖问题中,要用图示的4种不同形态的L型骨牌覆盖给定的特殊棋盘上除...

棋盘覆盖综合性问题,多种解法

综合性质的棋盘覆盖知识点,希望对你有帮助!!!

经典算法之棋盘覆盖问题 --分治法

一:算法分析 棋盘覆盖问题要求在2^k * 2^k 个方格组成的棋盘中,你给定任意一个特殊点,用一种方案实现对除该特殊点的棋盘实现全覆盖。 建立模型如图: 解决方案就是利用分治法,将方形棋盘分成4部...

0003算法笔记——【分治法】分治法与二分搜索,棋盘覆盖问题

1、分治法 分治法的基本思想是将一个规模为n的问题分解为k个规模较小的子问题,这些子问题相互独立且与原问题相同。递归的解这些子问题,然后将各子问题的解合并得到原问题的解。      分治法所能解决...

Delphi7高级应用开发随书源码

  • 2003年04月30日 00:00
  • 676KB
  • 下载

棋盘覆盖问题 题解

【问题描述】      在一个 2^k * 2^k 个方格组成的棋盘中,若恰有一个方格与其它方格不同,则称该方格为一特殊方格,称该棋盘为一特殊棋盘。显然特殊方格在棋盘上出现的位置有 4^k 种情形。...
  • PbTfcLx
  • PbTfcLx
  • 2016年01月10日 18:40
  • 1042

分治算法--棋盘覆盖

分治算法--棋盘覆盖   问题描述 在一个2^k×2^k 个方格组成的棋盘中,恰有一个方格与其他方格不同,称该方格为一特殊方格,且称该棋盘为一特殊棋盘。在棋盘覆盖问题中,要用图示的4种不同形...
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:分治法——棋盘覆盖问题
举报原因:
原因补充:

(最多只允许输入30个字)