22-09-14的华为笔试
有一吊桥共有N个木板,从吊桥一段的外侧开始跳(第0块),每一次可跳1、2、3步,其中有一些木板是陷阱,踩到即消耗一点生命值并在陷阱原地复活,刚好跳到吊桥的另一侧(第N+1块)则通关。
给定起始生命数量M(范围1-5),吊桥长度N(范围1-32),陷阱木板数量K(范围1-32)及K个陷阱木板的编号,求保证生命值大于0条件下所有可能的通关路线数量。
输入有如下的结构:
其中L是缺失木板的编号数组
M N K
L
样例1:
输入: 2 2 1
2
输出: 4
解释: 2个生命,2个木板,缺失1个木板,第二个木板有缺失,一共有4种走法。
1、 3
2、 1 2
3、 2 1
4、 1、1(复活)、1
样例2:
输入: 1 3 2
1 3
输出: 1
解释: 1个生命,3个木板,缺失2个木板,第1、3个木板有缺失,只有1种走法2 2。
1、先走1步,死亡;
1、先走3步,死亡;
思路:
- 定义一个dp二维数组,第一个维度表示在第i块木板上,第二个维度表示当前所拥有的生命值
- 则dp[i][j]为到达第i块木板,拥有生命值为j的方法数,dp[i][j]转移方程为dp[i][j]=dp[i-1][j1]+dp[i-2][j2]+dp[i-3][j3]
- 其中如果当前第i块木板是陷阱,那么从上一个木板过来需要j1=j+1,j2,j3同理
- 初始化dp数组为dp[0][M]=1
代码
public int handler(int M, int N, int K, int[] L) {
//初始化为0-N+1块木板
boolean[] bridge = new boolean[N + 2];
for (int ele : L) {
bridge[ele] = true;
}
int[][] dp = new int[N + 4][M + 2];
dp[2][M] = 1;//这是第0块木板的初始化,多两块是为了防止判断i<0的情况
for (int i = 3; i < N + 4; i++) {
for (int j = 1; j < M + 1; j++) {
//当前的第i块木板是缺失的
if (bridge[i - 2]) dp[i][j] = dp[i - 1][j + 1] + dp[i - 2][j + 1] + dp[i - 3][j + 1];
else dp[i][j] = dp[i - 1][j] + dp[i - 2][j] + dp[i - 3][j];
}
}
//最后需要求和,是因为到达第N+1块板子之后,可能会有1-M条命,那么把所有情况相加即可
int sum = 0;
for (int i = 1; i < M + 1; i++) {
sum += dp[N + 3][i];
}
return sum;
}