【DP】楼梯

一道关于楼梯问题的动态规划(DP)题目,描述了有n个楼梯,跳跃高度从1开始,每次乘2,求到达第n层的最短步数。题目提供了输入输出样例和数据范围,并提示了解题思路,包括如何根据条件划分情况进行DP求解。
摘要由CSDN通过智能技术生成

题目大意

就是有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;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值