【限时免费】20天拿下华为OD笔试之【DP】2023Q2-超级玛丽过吊桥-200分【欧弟算法】全网注释最详细分类最全的华为OD真题题解

【DP】2023Q2-超级玛丽过吊桥

题目描述与示例

题目描述

超级玛丽好不容易来到新的一关。有一个长长的吊桥共有 N 个木板,从吊桥一段的外侧开始跳(第 0 块),每一次可跳 123 步,其中有一些木板是陷阱,踩到即消耗一点生命值并在陷阱原地复活,刚好跳到吊桥的另一侧(第 N+1 块)则通关。 给定起始生命数量 M ,吊桥长度 N,陷阱木板数量 KK 个陷阱木板的编号,求保证生命值大于 0 条件下所有可能的通关路线数量。

输入描述

超级玛丽当前生命数:1 <= M <= 5 吊桥的长度:1 <= N <= 32 陷阱木板数:1 <= K <= 32 陷阱木板编号数组: L 是长度及元素不大于 N 的编号数组

输入结构

M N K` `L

提示

  1. 输入总是合法,忽略参数校验。
  2. 必须从起点开始走。
  3. 必须离开吊桥走到终点。

输出描述

输出通过此关的吊桥走法个数,如果不能通过此关,请输出 0

示例一

输入

2 2 1
2

输出

4

说明

2 个生命,2 个木板,缺失 1 个木板,第 2 个木板有缺失,一共有 4 种走法:

  1. 3
  2. 1 2
  3. 2 1
  4. 1 1(复活) 1

示例二

输入

1 3 2
1 3

输出

1

说明

1 个生命,3 个木板,缺失 2 个木板,第 13 个木板有缺失,只有 1 种走法,其他走法都不能通关。

  1. 先走一步,死亡;
  2. 先走三步,死亡。

示例三

输入

3 10 24
4 7

输出

504

解题思路

如果本题没有剩余生命值和陷阱木板的限制,那么这题会是一道非常简单的题目,可以看作是泰波那契版本的LC70. 爬楼梯。但加上限制之后,题目变得复杂了很多。

这是一个典型的序列dp问题。我们考虑动态规划三部曲:

  1. dp数组的含义是什么?

对于dp[i],不仅要记录到达第i块木板能够到达的方法数,还要记录到达该块木板时的剩余生命值。因此dp[i]可以存入一个哈希表,其中key为剩余生命值rest_lifevalue为以rset_life到达位置i的方法数。

  1. 动态转移方程是什么?

跳跃到第i块木板的方法数,为跳到第i-1i-2i-3块木板的方法数的总和。另外,还需要考虑第i块木板是否是陷阱木板。若

  • i块木板不是陷阱木板,那么不会损失生命,故存在dp[i][rest_life] += dp[j][rest_life]
  • i块木板是陷阱木板,那么会损失生命。故存在dp[i][rest_life-1] += dp[j][rest_life]。注意必须满足rest_life-1 > 0,这是因为如果跳跃到该陷阱木板后,剩余生命值降为0,那么不能考虑该跳跃。
for i in range(1, N+2):
    for j in range(max(0, i-3), i):
        for rest_life in dp[j]:
            if i not in L:
                dp[i][rest_life] += dp[j][rest_life]
            else:
                if rest_life-1 > 0:
                    dp[i][rest_life-1] += dp[j][rest_life]
  1. dp数组如何初始化?

起点只有一种情况,即以初始生命值M出现在起点。故以如下方式进行初始化

dp = [defaultdict(int) for _ in range(N+2)]
dp[0] = {M: 1}

代码

from collections import defaultdict

# 初始生命值M,吊桥长度N,陷阱木板的个数K
M, N, K = map(int, input().split())
# 陷阱木板的编号集合
L = set(map(int, input().split()))

# 初始化dp数组,dp[i]是一个哈希表,其中的
# key为剩余生命值rest_life,
# value为以rest_life到达吊桥位置i的方式数
dp = [defaultdict(int) for _ in range(N+2)]
# 初始化起点,只有一种情况
# 即以初始生命值M出现在起点
dp[0] = {M: 1}

# 从1开始,遍历包括终点N+1在内的所有位置
for i in range(1, N+2):
    # 考虑i的前三个位置,即i-1,i-2和i-3
    for j in range(max(0, i-3), i):
        # 遍历dp[j]哈希表中的所有剩余生命值rest_life
        for rest_life in dp[j]:
            # 第i块木板不是陷阱木板,走到i仍剩余生命值是rest_life
            if i not in L:
                # 更新dp[i][rest_life]
                dp[i][rest_life] += dp[j][rest_life]
            # 第i块木板是陷阱木板,走到i是剩余生命值是rest_life-1
            else:
                # 如果剩余生命值仍然大于0
                if rest_life-1 > 0:
                    # 更新dp[i][rest_life-1]
                    dp[i][rest_life-1] += dp[j][rest_life]

# dp结束后,dp[N+1]哈希表中的所有value求和,即为到达终点的方式数
print(sum(dp[-1].values()))

时空复杂度

时间复杂度:O(NM)。对整个吊桥仅需做一次遍历,但每一个位置i的动态转移过程都要遍历之前三个位置的哈希表,哈希表最大长度为初始生命值M,即储存了剩余生命值为1M的方法数目。

空间复杂度:O(NM)。dp数组所占据的空间。

华为OD算法/大厂面试高频题算法练习冲刺训练

  • 华为OD算法/大厂面试高频题算法冲刺训练目前开始常态化报名!目前已服务100+同学成功上岸!

  • 课程讲师为全网50w+粉丝编程博主@吴师兄学算法 以及小红书头部编程博主@闭着眼睛学数理化

  • 每期人数维持在20人内,保证能够最大限度地满足到每一个同学的需求,达到和1v1同样的学习效果!

  • 60+天陪伴式学习,40+直播课时,300+动画图解视频,300+LeetCode经典题,200+华为OD真题/大厂真题,还有简历修改、模拟面试、专属HR对接将为你解锁

  • 可上全网独家的欧弟OJ系统练习华子OD、大厂真题

  • 可查看链接 OD算法冲刺训练课程表 & OD真题汇总(持续更新)

  • 绿色聊天软件戳 od1336了解更多

你可能感兴趣的:(最新华为OD真题,#,dp,华为od,leetcode,动态规划)