电话线路

一.题目大意

       新的电话线架设在己有的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;
}

  

猜你喜欢

转载自blog.csdn.net/weixin_43823476/article/details/85095952