棋盘覆盖问题题解

文章目录


问题

在一个2k × 2k个方格组成的棋盘中,若恰有一个方格与其他方格不同,则称该方格为一特殊方格,且称该棋盘为一特殊棋盘。现用若干个L型骨牌覆盖在一个给定的特殊棋盘上除特殊方格以外的所有方格,且任何2个L型骨牌不得重叠覆盖

我们先来看一个k = 2时的棋盘覆盖问题

1

而骨牌的形状如下

2

对于k = 2的特殊棋盘,使用的骨牌数为 (22 × 22 -1) /3 = 5个

  • 同理递推到k = n 的特殊棋盘中,使用的骨牌数为**(2n × 2n - 1)/3 个**

那我们怎么去解决这个问题呢?

如果采用分治的思想去看这个问题的话,就应该是去将一个2k × 2k 的特殊棋盘分解成子问题,而这个子问题应该就是将棋盘等分成4个2k-1 × 2k-1相同规模的棋盘。

但是这里就出现了问题,可以很明显的发现,我们划分出来的子问题和原问题不是同相同的问题。子问题中特殊方格一定存在于4个子棋盘中的任意1个,但是其他3个棋盘中不存在特殊方格,也就不再是特殊棋盘,因此这两个子问题是不同的

如何解决这个问题?

我们可以通过一个L型的骨牌来使得4个相同规模的子问题相同,即将其他的3个棋盘也加上特殊方格

3

因此这个问题就变得容易解决了,在每次将问题分解成子问题时,就在其他3个方格的中心角处加上特殊方格,直到k = 1时,即2 × 2的棋盘

代码

以该棋盘为例

1

最终输出

2   2   3   3   
2   1   1   3   
4   1   0   5   
4   4   5   5 
#include <iostream>
#include <cstdio>
using namespace std;

#define BOARD_SIZE 4
int board[BOARD_SIZE][BOARD_SIZE];

// tc, tr: 棋盘左上角的行号和列号
// dc, dr: 特殊方格的行号和列号
// size = 2 ^ k
int tile = 1;    //tile为当前骨牌的号数
void chessboard(int tr, int tc, int dr, int dc, int size)
{
    if(size == 1) return;
    int s;
    int d = tile++; //d为L型骨牌号
    s = size / 2;
   
    //特殊方格在左上角子棋盘
    if(dr < tr + s && dc < tc + s)
    {
       chessboard(tr, tc, dr, dc, s);
    }
    else   // 不在此棋盘,将此棋盘右下角设为相应的骨牌号
    {
       board[tr + s - 1][tc + s - 1] = d;
       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] = d;
       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] = d;
       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] = d;
       chessboard(tr + s, tc + s, tr + s, tc + s, s);
    }
}

int main()
{
    int i, j;
    board[2][2] = 0;
    chessboard(0, 0, 2, 2, BOARD_SIZE);
    for(i = 0; i < BOARD_SIZE; i++)
    {
        for(j = 0; j < BOARD_SIZE; j++)
        {
           printf("%-4d", board[i][j]);
        }
        printf("\n");
    }
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

省下洗发水钱买书

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值