zoukankan      html  css  js  c++  java
  • poj 3612 Telephone Wire 分开绝对值,滚动数组DP

      状态 dp[i][j] 表示 第i根柱子,高度为j的最小花费

      转移方程

        dp( i , j ) = Min { dp( i-1, k ) + | k - j | * C + ( j-a[i] )*( j-a[i])  }

      如果我们 枚举 j 和 k, 因为 都小于 100,  时间复杂度也有 O( 10^9 ), 1000 ms也不够.

      

      我们可以把绝对值拆分开来:

      当 j >= k 时:

          dp( i, j ) = Min{ dp( i-1, k ) - k*C + j*c + ( j-a[i])^2 }

      当 j <= k 时:

          dp( i, j ) = Min{ dp( i-1, k ) + k*C + j*C + (j-a[i])^2 }

      可以观察到对于 j 而言, 只有 

          dp( i-1, k ) - k*C 

          dp( i-1, k ) + k*C

      是变化的.  而后面部分相对 每一个不同J的固定的.

      所以我们可以设定 函数 F,G :

      G( j ) = Min { dp( i-1, k ) + k*C }      其中k 属于 [ j, 100 ] 区间

      F( j ) = Min { dp( i-1, k ) - k*C  }  其中k 属于 [ a[i-1], j ] 区间

      所以最终结果为

        dp ( i, j ) = Min{ G(j)  - j*C , F(j) + j*C  } + ( j-a[i] )^2

      注意 因为 J 属于 区间 [ a[i-1], MaxHigh ]区间,  当J < a[i-1] 时要特殊处理

      

      对于dp状态表示,因为我们只要相邻的两组状态,所以可以用滚动数组来优化空间

    View Code
    #include<cstdio>
    #include<cstdlib>
    #include<cstring>
    
    #define MIN(a,b) (a)<(b)?(a):(b)
    #define MAX(a,b) (a)>(b)?(a):(b)
    const int N = 100100;
    const int inf = 0x3fffffff;
    
    int a[N], dp[2][200], f[200], g[200];
    int n, c, m;
    
    int main()
    {
        while( scanf("%d%d", &n,&c) != EOF)
        {
            m = 0;    
            for(int i = 1; i <= n; i++)
            {    
                scanf("%d", &a[i]);
                m = MAX( m, a[i] );    
            }    
            int cur = 0;
    
            for(int h = 0; h <= m; h++)
                if( h >= a[1] ) dp[cur][h] = (h-a[1])*(h-a[1]);
                else    dp[cur][h] = inf;
    
            for(int i = 2; i <= n; i++)
            {
                for(int h = 0; h <= m+1; h++)
                {
                    f[h]=g[h] = inf;
                    dp[!cur][h] = inf;    
                }
                // 函数f(k) 保存 区间 [ k, m ] 之间 MIN { dp[i-1,j] + j*c }     
                for(int h = m; h >= a[i-1]; h--)
                    f[h] = MIN( f[h+1], dp[cur][h]+h*c );    
                // 函数g(k) 保存 区间 [ a[i-1], k ] 之间 MIN { dp[i-1,j] - j*c }
                for(int h = a[i-1]; h <= m; h++)
                    g[h] = MIN( g[h-1], dp[cur][h]-h*c );
    
                for(int h = a[i]; h <= m; h++)
                {
                    if( h < a[i-1] ) 
                        dp[!cur][h] = MIN( dp[!cur][h], f[a[i-1]] - h*c + (a[i]-h)*(a[i]-h) );    
                    else
                        dp[!cur][h] = MIN( dp[!cur][h] , MIN( f[h]-h*c , g[h]+h*c ) + (a[i]-h)*(a[i]-h) );
                }    
                cur = !cur;    
            }    
            int ans = inf;
            for(int h = a[n]; h <= m; h++)
                ans = MIN( ans, dp[cur][h] );
            printf("%d\n", ans );    
        }
        return 0;
    }
  • 相关阅读:
    日常排版--word中的一些小技巧(交叉引用)
    各种中文乱码解决办法
    SpringBoot @RequestBody 中文乱码
    转:十大经典排序算法(动图演示)
    阿里云服务器,无法通过公网ip访问实例
    Attribute meta-data#android.support.VERSION@value value=(25.4.0) from AndroidManifest.xml:25:13-35 is also present at AndroidManifest.xml:28:13-35 value=(26.1.0).
    synchronized用法详解
    错误:(26, 13) Failed to resolve: com.android.support:appcompat-v7:27.+
    HashMap的clear方法
    SSM之全局异常处理器
  • 原文地址:https://www.cnblogs.com/yefeng1627/p/2853537.html
Copyright © 2011-2022 走看看