迷之阶梯(动态规划)

迷之阶梯

Luogu P2433

题目描述

吴思宇 需要通过一段迷之阶梯。登上阶梯必须要按照它要求的方法,否则就无法登上阶梯。它要求的方法有以下三个限制:

如果下一步阶梯的高度只比当前阶梯高1,则可以直接登上。

除了第一步阶梯外,都可以从当前阶梯退到前一步阶梯。

当你连续退下 k 后,你可以一次跳上不超过当前 阶梯高度 2^k 的阶梯。
比如说你现在位于第 j步阶梯,并 且是从第j+k步阶梯退下来的。那么你可以跳到高度不 超过当前阶梯高度 + 2^k 的任何一步阶梯。

跳跃这一次只 算一次移动。

开始时吴思宇在第 1 步阶梯。

由于时间紧迫(急着~~,吴思宇需要计算 出登上迷之阶梯的最少移动次数。

输入输出格式

输入格式:
第 1 行:一个整数 N,表示阶梯步数;

第 2 行:N 个整数(每两个之间有 1 个空格),依次为每层阶梯的高度,保证递增。

输出格式:
输出格式

1 行,一个整数,如果能登上阶梯,输出最小步数, 否则输出-1。

输入输出样例

输入样例#1:
5
0 1 2 3 6
输出样例#1:
7

思路

这个题是一道动态规划,如果相邻阶梯差值为1,f[i]就可以从f[i-1]转移而来。
枚举从退到哪个点然后2^len跳过来,我们可以先求出这个len
len=ceil(log(a[i]-a[j])/log(2));前提是i-j>=len,因为从f[j+len]回退回来,这样f[i]就可以从f[j+len]转移而来,在f[j+len]基础上+len+1。

代码

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<algorithm>
#include<cstring>
#include<cmath>
#define LL long long
using namespace std;
long long i,j,n,t,k,a[201],f[201],g[201];
long long r()
{
    long long ans=0,f=1;
    char ch=getchar();
    while(ch<'0'||ch>'9')
    {
        if(ch=='-')
        f=-1;
        ch=getchar();
    }
    while(ch>='0'&&ch<='9')
    {
        ans*=10;
        ans+=ch-'0';
        ch=getchar();
    }
    return ans*f;
}

int main()
{
    n=r();
    for(i=1;i<=n;i++)
    {
        a[i]=r();
        g[i]=i;
    }

    for(i=n;i>=2;i--)
    {
        if(a[i]-a[i-1]==1)
        {
            g[i-1]=g[i];
        }
    }

    memset(f,0x7f7f7f,sizeof(f));
    f[1]=0;
    int len=0;
    for(i=1;i<=n;i++)
    {
        if(a[i]-a[i-1]==1)
        f[i]=min(f[i],f[i-1]+1);
        for(j=1;j<i;j++)
        {
            len=ceil(log(a[i]-a[j])/log(2));//需要回退多少下 
            if(j+len<=i)//回退下数 
            {
                f[i]=min(f[i],f[j+len]+len+1);
            }
        }
    }
    if(f[n]!=9187201950435737471)
    cout<<f[n];
    else
    cout<<-1;

    return 0;
}
/*
6 3 6
1 0 1 0 1 1

1 1 1 1 0 0
0 0 0 1 0 1
0 0 1 1 1 1
*/

这里写图片描述

猜你喜欢

转载自blog.csdn.net/Stockholm_Sun/article/details/78327194