题目大意
就是有n个楼梯,开始的跳跃高度初始值是1,往后跳一层时,目前的跳跃高度就乘2,当跳跃只能跳跃到当前能跳到楼梯,跳跃之后的跳跃高度变成了初始值1…问跳到第n层最少花几步…
输入样例
5
0 1 2 3 6
输出样例
7
数据范围
- 2 <= N <= 50
高度是升序的
0 <= H[i] <= 1000000000
H[1]一定等于0
提示
输入: 输出:
5 7
0 1 2 3 6
解释:
往上走3步,后退3步,最后一步到达第N级楼梯.
输入: 输出:
5 9
0 1 2 4 8
解释:
往上走2步,后退2步,往上走1步到达高度是4的楼梯,后退3步,最后一步到达第N级楼梯.
输入: 输出:
8 -1
0 2 3 4 5 6 7 8
解释:
第1步就没法走了.
输入: 输出:
7 -1
0 1 2 3 5 10 100
解释:
第1步就没法走了.
输入: 输出:
15 36
0 1 2 3 4 7 10 15 50 100 200 300 400 500 1000
解题思路
- 其实这是一个多个DP,只要按着题目给的条件来打就行了
重点就是要分好情况来做就可以了…
程序如下
- 常规做法:
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
int n,a[10001],f[10001],t;
int main()
{
// freopen("c.in","r",stdin);
// freopen("c.out","w",stdout);
scanf("%d",&n);
for(int i=1;i<=n;++i)
scanf("%d",&a[i]);
memset(f,0x7f,sizeof(f));
f[1]=0;
for(int i=2;i<=n;++i)//普通跳
{
if(a[i]==a[i-1]+1)//看是否可以跳
f[i]=f[i-1]+1;
else break;//不行就返回
}
for(int i=2;i<n;++i)//从i开始继续
{
if(f[0]!=f[i])//看是否已经跳了过去,如果跳了就可以跳回去
{
t=1;
for(int j=i-1;j>0;--j)//枚举跳了j步
{
t*=2;//不断来增加往后跳的步数
for(int k=i+1;k<=n;++k)
{
if(a[k]-a[j]<=t) //看是否跳到之前的后面
f[k]=min(f[k],f[i]+(i-j)+1);//找最优的
else break;//找不到就退出
}
}
for(int j=i+1;j<=n;++j)//如果跳就直接跳
{
if(a[j]==a[j-1]+1)
f[j]=min(f[j],f[j-1]+1);//最优的
}
}
}
if(f[n]==f[0]) printf("-1");//如果等于说明跳不了就输出-1
else printf("%d",f[n]);
return 0;
}
- 大佬教的简单却难懂的方法:
#include<iostream>
#include<algorithm>
#include<cstdio>
#include<cstring>
using namespace std;
int a[1001],b[1001],n;
int main()
{
// freopen("c.in","r",stdin);
// freopen("c.out","w",stdout);
scanf("%d",&n);
for(int i=1;i<=n;++i)
scanf("%d",&a[i]);
memset(b,0x7f,sizeof(b));
b[1]=0;
for(int i=1;i<=n;++i)//和上一个程序是简化了的
{
for(int j=0;i-j>0;++j)
{
for(int k=i+1;k<=n;++k)
{
if(a[i-j]+(1<<j)>=a[k])//《--难点
b[k]=min(b[k],b[i]+j+1);
}
}
}
if(b[0]!=b[n]) printf("%d",b[n]);
else printf("-1");
return 0;
}