题目
好不容易来到新的一关,有一个长长的吊桥,吊桥的尽头是下水管道,其中随机的木板存在缺失,一旦踩到就会死亡,死亡后如果还有剩余的生命将在
原地复活且不受木板缺失影响,但会消耗一次生命;如果跨过了管道,将跌入县崖,通关失败。超级玛丽从起点 S 开始,可以走到下一个木板(计 1), 也可以跳着跨过一个块(计 2)或两个木板(计 3),最终必须刚好走到终点 E. 现在给定超级玛丽当前的生命数 M,吊桥的长度 N,缺失的木板数 K,以及随机缺失的木板
编号数组 L,请帮忙计算一下,超级玛丽有多少种方法可以通过此关。
解答要求
时间限制:CIC++1000ms,其他语言:2000ms 内存限制:CIC++256MB,其他语
言:512MB
输入
超级玛丽当前生命数:M(1<=M<=5,整数)吊桥的长度:N(1=N<=32,整数)
缺失木板数:K(1<=N<=32,整数)
缺失木板编号数组:L(长度及编号的内容不大于 N 的编号数组,1<=L<=N,由空格分隔的
整数数组)
输入结构:
M N K
L
提示:
1.输入总是合法,忽略参数校验。
2 必须从起点开始走。
3.必须离开吊桥走到终点。
输出
输出通过此关的吊桥走法个数,如果不能通过此关,请输出 0
样例 1
输入:
2 2 1
2
输出: 4
解释:2 个生命,2 个木板,缺失 1 个木板
第 2 个木板有缺失,一共有 4 种走法:
13
21,2
32,1
41,1(复活).1
样例 2
输入:
1 3 2
1 3
输出:1
解释:1 个生命,3 个木板,缺失 2 个木板
第 1 个和第 3 个有缺失
只有一种走法:2,2.其他都不能通关:
1 先走 1 步,死亡;
2 先走 3 步,死亡;
参考代码
不像普通的动态规划,而是很巧妙的使用map作为dp数组
package RealTest;
/**
* @ClassName superMary
* @Description TODO
* @Author 21916
* @Date 2024/3/14 9:00
*/
import java.util.*;
import java.io.*;
public class superMary {
public static void main(String[] args) throws IOException {
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
String[] input = br.readLine().split(" ");
int M = Integer.parseInt(input[0]); // 初始生命值
int N = Integer.parseInt(input[1]); // 吊桥长度
int K = Integer.parseInt(input[2]); // 陷阱木板的个数
Set<Integer> L = new HashSet<>();
String trapInput = br.readLine();
String[] trapSplit = trapInput.split(" ");
for (String s : trapSplit) {
L.add(Integer.parseInt(s));
}
// dp数组
Map<Integer, Map<Integer, Integer>> dp = new HashMap<>();
for (int i = 0; i <= N + 1; i++) {
dp.put(i, new HashMap<>());
}
// 初始化起点
dp.get(0).put(M, 1);
// 遍历吊桥上的每个位置
for (int i = 1; i <= N + 1; i++) {
// 遍历i的前三个位置
for (int j = Math.max(0, i - 3); j < i; j++) {
// 遍历dp[j]中所有的剩余生命值
for (Map.Entry<Integer, Integer> entry : dp.get(j).entrySet()) {
int rest_life = entry.getKey();
int ways = entry.getValue();
// 如果第i块木板不是陷阱木板
if (!L.contains(i)) {
// 更新dp[i][rest_life]
dp.get(i).put(rest_life, dp.get(i).getOrDefault(rest_life, 0) + ways);
}
// 如果第i块木板是陷阱木板,并且剩余生命值大于0
else if (rest_life - 1 > 0) {
// 更新dp[i][rest_life-1]
dp.get(i).put(rest_life - 1, dp.get(i).getOrDefault(rest_life - 1, 0) + ways);
}
}
}
}
// 累加dp[N+1]中所有值,得到到达终点的方式数
int totalWays = 0;
for (int count : dp.get(N + 1).values()) {
totalWays += count;
}
System.out.println(totalWays);
br.close();
}
}