zoukankan      html  css  js  c++  java
  • UESTC我要长高 DP优化

    Description

    韩父有N个儿子,分别是韩一,韩二…韩N。由于韩家演技功底深厚,加上他们间的密切配合,演出获得了巨大成功,票房甚至高达2000万。舟子是名很有威望的公知,可是他表面上两袖清风实则内心阴暗,看到韩家红红火火,嫉妒心遂起,便发微薄调侃韩二们站成一列时身高参差不齐。由于舟子的影响力,随口一句便会造成韩家的巨大损失,具体亏损是这样计算的,韩一,韩二…韩N站成一排,损失即为C*(韩i与韩i+1的高度差(1<=i<N))之和,搞不好连女儿都赔了.韩父苦苦思索,决定给韩子们内增高(注意韩子们变矮是不科学的只能增高或什么也不做),增高1cm是很容易的,可是增高10cm花费就很大了,对任意韩i,增高Hcm的花费是H^2.请你帮助韩父让韩家损失最小。

    Input

    有若干组数据,一直处理到文件结束。
    每组数据第一行为两个整数:韩子数量N(1<=N<=50000)和舟子系数C(1<=C<=100)
    接下来N行分别是韩i的高度(1<=hi<=100)。

    Output

    对每组测试数据用一行输出韩家的最小损失。

    Sample Input

    5 2
    2
    3
    5
    1
    4

    Sample Output

    15

    这题算是一个红果果的动态规划题了,但是很明显普通的做法是一个O(n^3)的算法,所以需要对这个动态规划过程进行单调队列优化。这里其实也就保留一个值就够了。详见代码:

    #include <cstdlib>
    #include <cstdio>
    #include <cstring>
    #include <algorithm>
    #define INF 0x3fffffff
    #define MAXN 50005
    using namespace std;
    
    int N, M, H[MAXN], dp[MAXN][105];
    // dp[i][j] 第i个人身高为j时的最少代价
    // 当前面的身高小于其身高时 
    // dp[i][j] = min( dp[i-1][k] + Mj - Mk + (j - H[i])^2 )同理
    // 对于上面的式子我们只需要维护好上一次状态的 dp[i-1][k]-Mk 的最小值就可以了
    // dp[i][j] = min( dp[i-1][k] + Mk - Mj + (j - H[i])^2 );
    // 对于上面的式子我们只需要维护好上一次状态的 dp[i-1][k]+Mk 的最小值就可以了
    
    int main()
    {
        int LIM, Min;
        while (scanf("%d %d", &N, &M) == 2) {
            LIM = -INF;
            for (int i = 1; i <= N; ++i) {
                scanf("%d", &H[i]);
                LIM = max(LIM, H[i]); // 最优解一定不会超过最高的一个人的高度 
            } 
            for (int i = 0; i <= N; ++i) {
                memset(dp[i], 0x3f, sizeof (dp[i]));    
            } 
            for (int i = H[1]; i <= LIM; ++i) {  // i < H[i] 的状态的无意义的,因为身高不可变低 
                dp[1][i] = (i - H[1]) * (i - H[1]); 
            } 
            for (int i = 2; i <= N; ++i) {  // i 号已经提前进行了初始化,从2号开始
                Min = INF;  // 保留上一层的最小值
                for (int j = H[i-1]; j <= LIM; ++j) {
                    Min = min(Min, dp[i-1][j] - M*j); 
                    if (j >= H[i]) { 
                        dp[i][j] = Min + M*j + (j - H[i]) * (j - H[i]);
                    } 
                }
                Min = INF;
                for (int j = LIM; j >= H[i]; --j) {
                    Min = min(Min, dp[i-1][j] + M*j);
                    if (j >= H[i]) {
                        dp[i][j] = min(dp[i][j], Min - M*j + (j - H[i]) * (j - H[i]));
                    } 
                }
            }
            Min = INF;
            for (int i = H[N]; i <= LIM; ++i) {
                Min = min(Min, dp[N][i]);
            }
            printf("%d\n", Min);
        }
        return 0;    
    }
                                             
  • 相关阅读:
    mysql获取给定时间段内的所有日期列表
    mysql中的年,月,日统计以及日历表的实现
    MySQL5.7安装配置
    获取ip地址
    Intellij热部署插件JRebel
    IntelliJ IDEA2018版热部署jrebel插件安装使用教程
    idea插件篇之java内存分析工具(JProfiler)
    mysql中的整除,取余
    SIMD.mul (SIMD) – JavaScript 中文开发手册
    Java面试题 : 如何确保N个线程访问N个资源的同时又不导致死锁
  • 原文地址:https://www.cnblogs.com/Lyush/p/2644676.html
Copyright © 2011-2022 走看看