题目
小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");elseprintf("%d",min(dp[n][0],dp[n][1]));return 0;
}