• 【t092】迷之阶梯


    Time Limit: 1 second
    Memory Limit: 128 MB

    【问题描述】

    在经过地球防卫小队的数学家连续多日的工作之后,外星人发的密码终于得以破解。它告诉我们在地球某一处的古老遗迹中,存在
    有对抗这次灾难的秘密道具。防卫小队立刻派出了一个直升机小分队,迅速感到了这处遗迹。要进入遗迹,需要通过一段迷之
    阶梯。登上阶梯必须要按照它要求方法,否则就无法登上阶梯。它要求的方法有以下三个限制:
    1. 如果下一步阶梯的高度只比当前阶梯高1,则可以直接登上。
    2. 除了第一步阶梯外,都可以从当前阶梯退到前一步阶梯。
    3. 当你连续退下k后,你可以一次跳上不超过当前阶梯高度2^k的阶梯。比如说你现在位于第j步阶梯,并且是从第j + k步阶梯退下
    来的。那么你可以跳到高度不超过当前阶梯高度 + 2^k的任何一步阶梯。跳跃这一次只算一次移动。
    开始时我们在第1步阶梯。由于时间紧迫,我们需要用最少的移动次数登上迷之阶梯。请你计算出最少的移动步数。
    [数据范围]
    对于50%的数据:1 <= N <= 20
    对于100%的数据:1 <= N <= 200
    每步阶梯高度不超过2^31-1
    【输入格式】

    第1行:一个整数N,表示阶梯步数
    第2行:N个整数,依次为每层阶梯的高度,保证递增

    【输出格式】

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

    Sample Input

    5
    0 1 2 3 6

    Sample Output

    7

    【题目链接】:http://noi.qz5z.com/viewtask.asp?id=t092

    【题解】

    代码1
    动态规划
    设f[i]表示到第i级阶梯所需要的最小步骤数;
    f[i] = f[i-1]+1;(h[i]==h[i-1]+1);
    f[i] = min(f[i],f[j+k]+k+1);
    (这里k = log2(h[i]-h[j]),且j+k<=i-1)
    这里第二个方程相当于从第j+k个位置跳到了第j个位置,然后再跳到i位置;
    这里考虑的也是最后的结果吧;
    就是第i级阶梯是怎么样走过来的;
    从结果去想状态的转移;
    代码2是记忆化搜索
    需要调到2s才能出解

    【代码1】动态规划

    #include <cstdio>
    #include <cstring>
    #include <algorithm>
    #include <cmath>
    using namespace std;
    #define LL long long
    #define rep1(i,a,b) for (int i = a;i <= b;i++)
    #define rep2(i,a,b) for (int i = a;i >= b;i--)
    #define rei(x) scanf("%d",&x)
    
    const int dx[9] = {0,1,-1,0,0,-1,-1,1,1};
    const int dy[9] = {0,0,0,-1,1,-1,1,-1,1};
    const double pi = acos(-1.0);
    const int MAXN = 200+10;
    
    int n;
    int a[MAXN],f[MAXN],top[MAXN][32];
    LL two[32];
    
    int main()
    {
        //freopen("F:\rush.txt","r",stdin);
        two[0] = 1;
        rep1(i,1,31)
            two[i] = two[i-1]*2;
        rei(n);
        rep1(i,1,n) rei(a[i]);
        memset(f,0x3f3f3f3f,sizeof f);
        f[1] = 0;
        rep1(now,2,n)
        {
            if (a[now]==a[now-1]+1)
                f[now] = f[now-1]+1;
            rep1(i,1,now-1)
            {
                int d = a[now]-a[i],k;
                for (k = 0;k <= 31;k++)
                    if (two[k]>=d)
                        break;
                if (i+k<=now-1)
                    f[now] = min(f[now],f[i+k]+k+1);
            }
        }
        if (f[n]<0x3f3f3f3f)
            printf("%d
    ",f[n]);
        else
            puts("-1");
        return 0;
    }
    

    【代码2】记忆化搜索

    #include <cstdio>
    #include <algorithm>
    #include <cstring>
    #include <cmath>
    using namespace std;
    #define lson l,m,rt<<1
    #define rson m+1,r,rt<<1|1
    #define LL long long
    #define rep1(i,a,b) for (int i = a;i <= b;i++)
    #define rep2(i,a,b) for (int i = a;i >= b;i--)
    #define mp make_pair
    #define pb push_back
    #define fi first
    #define se second
    #define rei(x) scanf("%d",&x)
    #define rel(x) scanf("%I64d",&x)
    
    typedef pair<int,int> pii;
    typedef pair<LL,LL> pll;
    
    const int dx[9] = {0,1,-1,0,0,-1,-1,1,1};
    const int dy[9] = {0,0,0,-1,1,-1,1,-1,1};
    const double pi = acos(-1.0);
    const int MAXN = 200+10;
    
    int n;
    int a[MAXN],f[MAXN][32],top[MAXN][32];
    LL two[32];
    
    void dfs(int now,int k,int step)
    {
        if (f[now][k]<step)
            return;
        f[now][k] = step;
        if (now==n) return;
        int ma = top[now][k];
        rep2(i,ma,now+1)
            dfs(i,0,step+1);
        if (now>1)
            dfs(now-1,k+1,step+1);
    }
    
    int main()
    {
        //freopen("F:\rush.txt","r",stdin);
        two[0] = 1;
        rep1(i,1,31)
            two[i] = two[i-1]*2;
        rei(n);
        rep1(i,1,n) rei(a[i]);
        rep1(i,1,n)
        {
            if (a[i+1]==a[i]+1)
                top[i][0] = i+1;
            else
                top[i][0] = i;
            rep1(j,1,31)
            {
                LL ma = a[i]+two[j];
                int k;
                for (k = top[i][j-1];k <= n;k++)
                    if (ma<a[k])
                        break;
                top[i][j] = k-1;
            }
        }
        memset(f,0x3f3f3f3f,sizeof f);
        dfs(1,0,0);
        if (f[n][0]<0x3f3f3f3f)
            printf("%d
    ",f[n][0]);
        else
            puts("-1");
        return 0;
    }
  • 相关阅读:
    Oracle查询数据表结构/字段/类型/大小
    Oracle 如何修改列的数据类型
    数组声明和使用要点
    关于转发和重定向的路径问题!
    Java高级架构师(一)第29节:完成下订单和修改库存的功能
    Java高级架构师(一)第28节:Index、商品详细页和购物车
    Java高级架构师(一)第27节:实现index功能的开发
    《深入理解Spark-核心思想与源码分析》(三)第三章SparkContext的初始化
    《深入理解Spark-核心思想与源码分析》(二)第二章Spark设计理念和基本架构
    《深入理解Spark-核心思想与源码分析》(一)总体规划和第一章环境准备
  • 原文地址:https://www.cnblogs.com/AWCXV/p/7626644.html
Copyright © 2020-2023  润新知