电话线路

一.题目大意

       新的电话线架设在己有的n根电话线杆上,第i根电话线的高度为hi, ( 1 <= hi<= 100)。电话线总是从一根电话线杆的顶端弓}到相邻的那根的顶端,如果这两根电话线杆的高度hi和hj不同,那么就必须支付c * |hi - hj|的费用,当然,你不能移动电话线杆,只能按照原有的顺序在相邻杆间架设电话线。加高某些电话线杆能减少架设电话线的总费用,尽管这项工作也需要支付一定的费用。更准确说,如果他把一根电话线杆加高x米的话,他需要付出x^2费用。如果合理的进行这两项工作,最少要在这个电话线改造工程中花多少钱。N <= 100000,  C <= 100 

二.基本思想

   这道题准确来说也是dp。

   我们可以定义dp[i][j]表示前i个电话线杆都达到j的高度所用的最少钱,于是就可以想到方程:

dp[i][j] = dp[i-1][k] + (h[i] - k)^{2} + c * \left | h[i]-j \right |

但是这里是三重循环,会超时。我们就可以将公式简化一下:

当h[i]>=j时:

dp[i][j] = dp[i-1][k] + c * h[i] + (h[i] - k)^{2} - j*c

就只需要保存前面两项的和最小值

当h[i]<j时:

dp[i][j] = dp[i-1][k] - c * h[i] + (h[i] - k)^{^{2}} + j * c

也就是一次大循环用一变量储存就可以啦

三.具体实现

  

#include <iostream>
#include <cstdio>
#include <cstring>
#include <cmath>
#include <algorithm>
#include <deque>
using namespace std;
const int MAXN =100003;
int n , c , dp[MAXN][103] ,h[MAXN] , maxh;
void read( int &x ){
    int f = 1 ; x = 0;
    char s = getchar();
    while( s < '0' || s > '9' ){
        if( s == '-' )
            f = -1;
        s = getchar();
    }
    while( s >= '0' && s <= '9' ){
        x = x * 10 + s - '0';
        s = getchar();
    }
    x *= f;
 
}
int pow_( int x ){
    return x * x;
}
int main(){
    read( n );read( c );
    for( int  i = 1 ; i <= n ; i ++ ){
        read( h[i] );
        maxh = max( maxh , h[i] );//先找出h[i]最大值
    }
    memset( dp , 0x3f , sizeof( dp) );//因为要找最小值,所以就要先清极大值
    for( int i = h[1] ; i <= maxh ; i++ )
        dp[1][i] = pow_( i - h[1] );//边界条件,因为第一个有点特殊,我们直接加它的平方即可
    for( int i = 2 ; i <= n ; i ++ ){
        int minn = 0x3f3f3f3f ;
        for( int j = 0 ; j <= h[i] ; j ++ )
            minn = min( minn , dp[i-1][j] - j * c );//先前找,因为这时j<=h[i],dp不会存在,
        for( int  j = h[i] ; j <= maxh ; j ++ )//但我们依然要去找最小值
            dp[i][j] = minn + j * c + pow_( j - h[i] );//这里是当k<=h[i]的方程
        minn = 0x3f3f3f3f;
        for( int j = maxh ; j >= h[i] ; j -- ){
            minn = min( dp[i-1][j] + j * c , minn );
            dp[i][j] = min( minn - j * c + pow_( j - h[i] ) , dp[i][j] );//k>h[i]
        }
    }
    int ans = 0x3f3f3f3f;
    for( int i = h[n] ; i <= maxh ; i ++ )
        if( dp[n][i] < ans )
            ans = dp[n][i];//最后找出最小值
    printf( "%d" , ans );
    return 0;
}

  

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值