Tromino谜题

Tromino谜题

问题描述

Tromino是指一个由棋盘上的三个方块组成的L型骨牌。如何用Tromino覆盖一个缺少了一个方块(可以在棋盘上任何位置)2n × 2n的棋盘(下图展示了情况)。除了这个缺失的方块,Tromino应该覆盖棋盘上的所有方块,Tromino可以任意转向但不能有重叠。

整个棋盘一共有2n × 2n即4n 个格子,除去缺失的洞之外,还剩下4n -1个格子。由数学归纳法可证,4ⁿ -1为3的倍数,所以有可能存在解法。

现将棋盘由两条中线划分为等大的4份,除去原有的洞所在的一份之外,其他三份的格子数为4n-1,需要各自挖一个新的洞使得解存在,所以在三份的相邻处,也就是原棋盘的中心位置,添上一个L型骨牌,使得原问题可以划分为更小的子问题。 这利用了分治法的思想,每次分治找出中心处L型骨牌的摆放位置,直到剩下1×1大小的子棋盘结束分治。

算法描述

记录棋盘为一个2n×2n 的二维数组“board = zeros((2n,2n))”,洞及它的坐标表示为“hole(i,j)”,并将上述分析过程和解决的思路进一步归纳为以下步骤:

(1)找到当前棋盘的中心位置,并判断该棋盘上洞的位置,以此为依据,划分棋盘为4份。

(2)除去原有的洞所在的一份之外,在其他三份的相邻处,也就是原棋盘的中心位置,添上一个L型骨牌,在每一份棋盘中根据洞的位置,继续划分。

(3)重复第(1)(2)步,直到棋盘大小为1×1结束递归。

复杂度分析

设问题规模为2^n×2^n,每次递归调用函数会执行(2^n×2^n)次递归停止判断,(1+4+4×4+...+4^(n-1))一共(4^(n-1))/3次递归,每次递归需要执行1~4次洞的位置判断(取决于缺失方块的位置,而缺失方块的位置是随机的),所以本算法的时间复杂度为4^n+(4^(n-1))/3*(1+2+3+4)/4,即θ(4^n)。

由于使用了递归,系统需要使用堆栈保存上一次递归的情况直到合并阶段,所以它的空间复杂度为4n+(1+4+4×4+...+4n-1),即θ(4^n)。

黄色点为原始缺失的方块,递归时用随机的颜色填充时子棋盘的中心。

可以从图2.1中看到,如果将将该算法以决策树的形式呈现,递归顺序可以形容为对递归树的深度优先遍历。

n=3时程序运行过程
 n=5时程序运行结果

代码:

import random
import numpy as np
import matplotlib.pyplot as plt
def tromino(pos_1, pos_2, hole):
    #递归停止条件
    if pos_1 == pos_2:
        return
    global board
    #随机颜色
    t = random.randint(0, 220)
    plt.clf()
    plt.imshow(board)
    plt.pause(0.02)
    #棋盘中心 偏向左上方
    center = (((pos_2[0]+pos_1[0])//2), ((pos_2[1]+pos_1[1])//2))
    #hole在左上方
    if hole[0]<=center[0] and hole[1]<=center[1]:
        board[center[0]][center[1]+1] = board[center[0]+1][center[1]] \
            = board[center[0]+1][center[1]+1] = t
        tromino(pos_1, center, hole)
        tromino((pos_1[0],center[1]+1), (center[0],pos_2[1]), (center[0], center[1]+1))
        tromino((center[0]+1,pos_1[1]), (pos_2[0],center[1]), (center[0]+1, center[1]))
        tromino((center[0]+1,center[1]+1), pos_2, (center[0]+1, center[1]+1))
    #hole在右上方
    elif hole[0]<=center[0] and hole[1]>center[1]:
        board[center[0]][center[1]] = board[center[0]+1][center[1]] \
            = board[center[0]+1][center[1]+1] = t
        tromino(pos_1, center, (center[0], center[1]))
        tromino((pos_1[0],center[1]+1), (center[0],pos_2[1]), hole)
        tromino((center[0]+1,pos_1[1]), (pos_2[0],center[1]), (center[0]+1, center[1]))
        tromino((center[0]+1,center[1]+1), pos_2, (center[0]+1, center[1]+1))
    #hole在左下方
    elif hole[0]>center[0] and hole[1]<=center[1]:
        board[center[0]][center[1]] = board[center[0]][center[1]+1] \
            = board[center[0]+1][center[1]+1] = t
        tromino(pos_1, center, (center[0], center[1]))
        tromino((pos_1[0],center[1]+1), (center[0],pos_2[1]), (center[0], center[1]+1))
        tromino((center[0]+1,pos_1[1]), (pos_2[0],center[1]), hole)
        tromino((center[0]+1,center[1]+1), pos_2, (center[0]+1, center[1]+1))
    #hole在右下方
    elif hole[0]>center[0] and hole[1]>center[1]:
        board[center[0]][center[1]] = board[center[0]+1][center[1]] \
            = board[center[0]][center[1]+1] = t
        tromino(pos_1, center, (center[0], center[1]))
        tromino((pos_1[0],center[1]+1), (center[0],pos_2[1]), (center[0], center[1]+1))
        tromino((center[0]+1,pos_1[1]), (pos_2[0],center[1]), (center[0]+1, center[1]))
        tromino((center[0]+1,center[1]+1), pos_2, hole)
if __name__ == '__main__':
    n = int(input('请输入规模:'))
    n = 2**n
    board = np.zeros((n,n))
    hole = (random.randint(0,n-1), random.randint(0,n-1))
    board[hole[0]][hole[1]] = 255
    fig = plt.figure()
    tromino((0,0), (n-1,n-1), hole)
    plt.imshow(board)
    plt.show()

 

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值