拼积木—— 不同条件下的暴力dfs or 动规

题目

小毛同学参加了搭积木竞赛,主办方提供了一个大小为Lx2(L<=4〉的矩形木框,比赛求用积木填满,不同的方案越多得分越高。一共有两种积木:2x2和1x2,积木的数目后做是无隙的。如果两种方案在某一个位置使用的积木类型不同或者摆放不同。即认为这两种方案是不同的。调问最多能有多少种不同的方票拉。

思路

考虑转移方程,若拼好以下标i为结尾的矩形木框,在拼最后一块时可以选择使用2×2大小的积木,也可以选择用两块1×2的积木横向,这两种都是由i-2转移而来;也可以选择用1×2的积木纵向,此时由i-1转移而来。于是得到转移方程:f(i) = f(i-2)*2 + f(i-1).

def scores(L):
    dp = [0]*(L+1)
    dp[0], dp[1] = 1, 1
    for i in range(2, L+1):
        dp[i] = dp[i-2]*2 + dp[i-1]
    return dp[-1]

scores(4)
## 11 

修改题目

Lx2 -> Lx3

思路

此时不能使用dp,只能dfs暴搜。具体来说,只要找到一个空格子,就需要摆放积木去填满,此时可以选择两种积木三种摆法,要根据边界条件确定所选摆法的正确性,然后dfs摆放剩余空格子。

  • 使用一个visit数组记录各个木框格子是否被占据。
  • 如何保证无重复且全计算:遍历顺序定义为从上至下,从左至右,每次空格子摆积木时默认当前空格子为积木的左上角。
  • 什么时候回溯:当找到空格子并试完三种摆放情况后,向上回溯。
  • 什么时候摆放方案+1:当找不到空格子时,说明木框全被积木填满,此时为一种摆放方案,得分+1
## L * 3
## 2 * 1, 2 * 2
def Scores(L):
    visit = [[0]*3 for _ in range(L)]
    global res
    res = 0
    def dfs(m, n):
        global res
        for i in range(m, L):
            for j in range(n, 3):
                if not visit[i][j]:
                    ## 2 * 2
                    if i+1 < L and j+1 < 3 and sum([visit[i+1][j], visit[i][j+1], visit[i+1][j+1]]) == 0:
                        visit[i][j], visit[i+1][j], visit[i][j+1], visit[i+1][j+1] = 1, 1, 1, 1
                        dfs(i, j)
                        visit[i][j], visit[i+1][j], visit[i][j+1], visit[i+1][j+1] = 0, 0, 0, 0
                    ## 2 * 1
                    if i+1 < L and not visit[i+1][j]:
                        visit[i][j], visit[i+1][j] = 1, 1
                        dfs(i, j)
                        visit[i][j], visit[i+1][j] = 0, 0
                    ## 1 * 2
                    if j+1 < 3 and not visit[i][j+1]:
                        visit[i][j], visit[i][j+1] = 1, 1
                        dfs(i, j)
                        visit[i][j], visit[i][j+1] = 0, 0
                    return
        res += 1
    dfs(0, 0)
    return res

Scores(10)
## 146
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值