递归与分治策略之棋盘覆盖问题

棋盘覆盖

       在一个2^k * 2^k 个方格组成的棋盘中,若恰好有一个方格与其他方格不同,则称该房改为一特殊方格,且称该棋盘为一特殊棋盘。显然特殊方格在棋盘上出现的位置有4^k种情况。

       在棋盘覆盖问题中,要用如下图所示的4种不同形态的L型骨牌覆盖一个给定的特殊棋盘上除特殊方格以外的所有方格,且任何2个L型骨牌不得重复覆盖。可知,在任何一个2^k * 2^k的棋盘覆盖中,用到的L型骨牌的个数恰为(4^k - 1)/3。

                            

                                                                      

特殊棋盘图

                                                                      

算法思想:用分治策略,可以设计解棋盘覆盖为题的一个算法。当k > 0时,将2^k * 2^k棋盘分割为4个2^k-1 * 2^k-1字棋盘,特殊方格必位于4个子棋盘之一中,其余3个子棋盘中无特殊方格。为了这3个无特殊方格的子棋盘转化为特殊棋盘,我们用一个L型骨牌覆盖这3个子棋盘的汇合处,如下图:

 

                                                                     

从而将原问题转化为4个子棋盘覆盖问题。递归的使用这种分割,直至棋盘简化为1*1棋盘。

 

       实现这种分治策略的算法可描述如下:

#include <iostream>
#include <cstring>

using namespace std;

const int MAX_SIZE = 10;

int tite = 1;
int board[MAX_SIZE][MAX_SIZE];

/*
函数名称:ChessBoard
函数功能:实现2^k * 2^k 的棋盘覆盖
函数参数:
        tr:棋盘左上角的行号
        tc:棋盘左上角的列号
        dr:特殊方格的行号
        dc:特殊方格的列号
        size:棋盘规格大小
        tite:L型骨牌的编号 其初始值为1 全局变量
返回值:无
*/

void ChessBoard(int tr, int tc, int dr, int dc, int size)
{
    if(size == 1)
        return ;
    int t = tite++;
    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 + s - 1), 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()
{
    int n = 0;
    while(cin >> n)
    {
        memset(board, -1, sizeof(board));
        board[2][2] = 0;
        ChessBoard(0, 0, 2, 2, n);

        for(int i = 0;i < n;++i)
        {
            for(int j = 0; j < n; ++j)
                cout << board[i][j];
            cout << endl;
        }
    }
    return 0;
}


 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值