• 19-魔法上楼梯


    /*                                                            魔法少女
                          时间限制:1000 ms  |  内存限制:65535 KB
                                 难度:3

    描述
        前些时间虚渊玄的巨献小圆着实火了一把。 在黑长直(小炎)往上爬楼去对抗魔女之夜时,她遇到了一个问题想请你帮忙。 因为魔女之夜是悬浮在半空的,所以她必须要爬楼,而那座废墟一共有n层,而且每层高度不同,这造成小炎爬每层的时间也不同。不过当然,小炎会时间魔法,可以瞬间飞过一层或者两层[即不耗时]。但每次瞬移的时候她都必须要至少往上再爬一层(在这个当儿补充魔力)才能再次使用瞬移。爬每单位高度需要消耗小炎1秒时间。 消灭魔女之夜是刻不容缓的,所以小炎想找你帮她找出一种最短时间方案能通往楼顶。

        输入
            本题有多组数据,以文件输入结尾结束。
            每组数据第一行一个数字N(1 <= N <= 10000),代表楼层数量。
            接下去N行,每行一个数字H(1 <= H <= 100),代表本层的高度。
        输出
            对于每组数据,输出一行,一个数字S,代表通往楼顶所需的最短时间。
        样例输入

            5
            3
            5
            1
            8
            4

        样例输出

            1



    题目的本质是:已知一个包含n个正整数的序列h[0],h[1]……h[n-1],求一个最小子序列,满足:
    (1) 子序列中任意相邻的两个数,在原序列中的位置差小于等于3
    (2) 所有满足条件(1)的序列中,最小子序列中的数的和最小。


    例如以下测试数据:
    10
    3 5 1 8 4 2 5 6 1 3
    有多种子序列选择,例如:
    3 5 1 8 4 2 5 6 1 3(全选,总和为38)
    3   1   4 2     1 3(和为14)
        1     2     1   (和为4)
    3       4 2     1   (非法,3和4在原序列中的位置差大于3)


    一般从活动的最后一步往前推导状态转移方程。
    直观地,我们会想到这样的状态转移方程:
    设f[i]表示在h[0...i]这个整数序列中,选出来的最小子序列是多少。f[i]的取值跟f[i-1],甚至f[i-2]、f[i-3]……有关。
    f[i] = min { f[i - 1] + h[i]; // 取第i个数
                 f[i - 1];   // 不取第i个数。oops!
                 ……}
    oops,我们在考虑不取第i个数的时候碰到问题了。因为我们不知道f[i-1]的最小子序列是怎么取的。如果f[i-1]的最小子序列没有取h[i-1]和h[i-2],那f[i]就不能等于f[i-1]了,否则违反条件(1)。
    所以这里我们需要改一下:设f[i]表示在h[0...i]中选出的最小子序列,且第i个数必选。于是,
    f[i] = min { f[i-1] , // 取f[i-1]
                 f[i-2] , // 不取f[i-1]了,取f[i-2]
                 f[i-3] , // f[i-1]和f[i-2]都不取,取f[i-3]
                } + h[i]; //h[i]必取
    我们知道,在h[0...n-1]取出来的子序列中,必满足以下三种情况之一:
    (1) 取h[n-1],则最小子序列为f[n-1]
    (2) 不取h[n-1], 取h[n-2],则最小子序列为h[n-2]
    (3) 不取h[n-1]和h[n-2],取h[n-3],则最小子序列为h[n-3]
    */


    #include <iostream>
    #include <cstdio>
    #include <cstring>
    using namespace std;
    int dp[10005];
    int a[10005];

    int main(){
        int n;
        while(~scanf("%d", &n)){
            memset(dp, 0x3f3f3f3f, sizeof(dp));
            for(int i = 3; i < 3 + n; i++)    
                scanf("%d", &a[i]);
            dp[0] = dp[1] = dp[2] = 0;
            a[0] = 0;
             for(int i = 3; i < 3 + n; i++){
                dp[i] = min(min(dp[i - 1], dp[i - 2]), dp[i - 3]) + a[i];
            }
            printf("%d ", min(min(dp[n + 2], dp[n + 1]), dp[n]));
        }
        return 0;
    }

    /*思路:用动态规划求解 dp[0][i]表示少女在i层,并且可以使用魔法,dp[1][i]表示少女在i层,但是不可以使用魔法

    状态转移方程:

                dp[1][i]=min(dp[0][i-2],dp[0][i-1]);
                dp[0][i]=min(dp[1][i-1]+a[i],dp[0][i-1]+a[i]);
    */

    #include <iostream>
    #include <cstdio>
    #include <cstring>
    using namespace std;
    int dp[2][10005];
    int a[10005];

    int main(){
        int n;
        while(~scanf("%d", &n)){
            memset(dp, 0, sizeof(dp));
            for(int i = 1; i <= n; i++){
                scanf("%d", &a[i]);
            }
            dp[0][0] = 0;
            dp[1][1] = dp[1][2] = 0;
            for(int i = 1; i <= n; i++){
                dp[0][i] = min(dp[0][i - 1], dp[1][i - 1]) + a[i];
                if(i >= 3)
                    dp[1][i] = min(dp[0][i-1], dp[0][i-2]);
            }
            printf("%d ", min(dp[0][n], dp[1][n]));
        }
        return 0;
    }

  • 相关阅读:
    SpringBoot项目部署与服务配置
    JDBC链接oracle已经mysql的测试
    Jedis工具类
    jsp&Sevelet基础详解
    Mysql和Oracle数据库concat()函数
    如何在maven工程中加载oracle驱动
    获取日期的相关方法
    SpringBoot配置Email发送功能
    spring中schedule注解的使用
    新建一个新的spring boot项目
  • 原文地址:https://www.cnblogs.com/zhumengdexiaobai/p/7429711.html
Copyright © 2020-2023  润新知