题目
小D接到一项任务,要求他爬到一座n层大厦的顶端与神秘人物会面。这座大厦有一个神奇的特点,每层的高度都不一样,同时,小D也拥有一项特殊能力,可以一次向上跳跃一层或两层,但是这项能力无法连续使用。已知向上1高度消耗的时间为1,跳跃不消耗时间。由于事态紧急,小D想知道他最少需要多少时间到达顶层。
输入
第一行包含一个整数n,代表楼的高度。
接下来n行每行一个整数ai,代表i层的楼层高度(ai <= 100)。
输出
输出1行,包含一个整数,表示所需的最短时间。
样例输入
5
3
5
1
8
4
样例输出
1
解题思路
本题可以用深度优先的搜索,但是可能会超时,更优的方法是使用动态规划。首先分析可以得到如下表格,表格中记录的数值是到当前层所需的最短时间(数据来自于样例):
层数 | 爬到到第i层(j=0) | 跳跃到第i层(j=1) |
---|---|---|
0 | 0 | 0 |
1 | 3 | 0 |
2 | 5 | 0 |
3 | 1 | 3 |
4 | 9 | 1 |
5 | 5 | 1 |
… | … | … |
n | min(dp[n-1][0],dp[n-1][1])+a[n] | min(dp[n-1][0],dp[n-2][0]) |
表格的"j=0"列,表示的是从上一次落脚的层,即第(i-1)层,是通过爬的方式到达当前层(第i层)的;"j=1"列,则代表小D是通过跳跃的方式,从上一次落脚的层,即(i-1)或者(i-2)层,到达第i层的。
因此,如果小D要前往第i层,如果选择爬,则上一步可以是跳跃,也可以是爬,那么之前的路线则选择耗时最短的,即总时间有min(dp[i-1][0],dp[i-1][1])+a[n]
(这里存在为什么向上爬都爬一层的问题,是因为题目要求耗时最短的,那么肯定减少爬的楼层数目);如果选择跳跃,那么上一步必然要是爬,且跳跃高度为1或2层,所以小D当前所处的楼层必然是(i-1)或者(i-2),因此,有min(dp[i-1][0],dp[i-2][0])
。将以上描述写为状态转移方程,有:
{
d
p
[
i
]
[
0
]
=
m
i
n
(
d
p
[
i
−
1
]
[
0
]
,
d
p
[
i
−
1
]
[
1
]
)
+
a
[
n
]
d
p
[
i
]
[
1
]
=
m
i
n
(
d
p
[
i
−
1
]
[
0
]
,
d
p
[
i
−
2
]
[
0
]
)
\left\{ \begin{aligned} &dp[i][0]= min(dp[i-1][0],dp[i-1][1])+a[n]\\ &dp[i][1]= min(dp[i-1][0],dp[i-2][0])\\ \end{aligned} \right.
{dp[i][0]=min(dp[i−1][0],dp[i−1][1])+a[n]dp[i][1]=min(dp[i−1][0],dp[i−2][0])
最终答案是min(dp[n][0],dp[n][1])。
代码
#include<stdio.h>
int min(int a, int b){
return (a>b)?b:a;
}
int main()
{
int n,i;//n表示楼层数
scanf("%d",&n);
int a[n+1],dp[n][2];
for (i=1;i<=n;i++)
scanf("%d",&a[i]);
dp[0][0]=0,dp[0][1]=0;
dp[1][0]=a[1],dp[1][1]=0;
for (i=2;i<=n;i++)
{
dp[i][0] = min(dp[i-1][0],dp[i-1][1])+a[i];
dp[i][1] = min(dp[i-1][0],dp[i-2][0]);
}
if (n>0 && n<=2)
printf("1");
else
printf("%d",min(dp[n][0],dp[n][1]));
return 0;
}