• BZOJ_1705_[Usaco2007 Nov]Telephone Wire 架设电话线_DP


    BZOJ_1705_[Usaco2007 Nov]Telephone Wire 架设电话线_DP

    Description

    最近,Farmer John的奶牛们越来越不满于牛棚里一塌糊涂的电话服务 于是,她们要求FJ把那些老旧的电话线换成性能更好的新电话线。 新的电话线架设在已有的N(2 <= N <= 100,000)根电话线杆上, 第i根电话线杆的高度为height_i米(1 <= height_i <= 100)。 电话线总是从一根电话线杆的顶端被引到相邻的那根的顶端 如果这两根电话线杆的高度不同,那么FJ就必须为此支付 C*电话线杆高度差(1 <= C <= 100)的费用。当然,你不能移动电话线杆, 只能按原有的顺序在相邻杆间架设电话线。Farmer John认为 加高某些电话线杆能减少架设电话线的总花费,尽管这项工作也需要支出一定的费用。 更准确地,如果他把一根电话线杆加高X米的话,他得为此付出X^2的费用。 请你帮Farmer John计算一下,如果合理地进行这两种工作,他最少要在这个电话线改造工程上花多少钱。

    Input

    * 第1行: 2个用空格隔开的整数:N和C

    * 第2..N+1行: 第i+1行仅有一个整数:height_i

    Output

    * 第1行: 输出Farmer John完成电话线改造工程所需要的最小花费

    Sample Input

    5 2
    2
    3
    5
    1
    4
    输入说明:
    一共有5根电话线杆,在杆间拉电话线的费用是每米高度差$2。
    在改造之前,电话线杆的高度依次为2,3,5,1,4米。


    Sample Output

    15
    输出说明:
    最好的改造方法是:Farmer John把第一根电话线杆加高1米,把第四根加高2米,
    使得它们的高度依次为3,3,5,3,4米。这样花在加高电线杆上的钱是$5。
    此时,拉电话线的费用为$2*(0+2+2+1) = $10,总花费为$15。


    分析:

    一般的DP:设f[i][j]表示前i根电线杆高度为j的最小花费。

    f[i][j]=min{f[i-1][k]+(k-a[i])^2+c*abs(j-k)。显然会T。

    考虑优化这个方程,我们把绝对值打开。

    if(k<=j) f[i][j]=f[i-1][k]-c*k+c*j+(k-a[i])^2

    else f[i][j]=f[i-1][k]+c*k-c*j+(k-a[i])^2

    f[i-1][k]-c*k和f[i-1][k]+c*k的最小值可以在求出f的时候同时更新。

    代码:

    #include <stdio.h>
    #include <string.h>
    #include <algorithm>
    using namespace std;
    #define N 100050
    #define mem(x) memset(x,0x3f,sizeof(x))
    int f[N], n, a[N], l[120], r[120], m, c;
    int main() {
    	scanf("%d%d", &n, &c);
    	int i, j;
    	for(i = 1;i <= n; ++ i) scanf("%d",&a[i]), m = max(m, a[i]);
    	memset(f, 0x3f, sizeof(f));
    	for(i = a[1];i <= m; ++ i) f[i] = (i - a[1]) * (i - a[1]);
    	for(i = 2;i <= n; ++ i) {
    		mem(l);
    		mem(r);
    		for(j = a[i - 1];j <= m; ++ j) {
    			l[j] = min(l[j - 1], f[j] - c * j);
    		}
    		for(j = m;j >= a[i - 1]; -- j) {
    			r[j] = min(r[j + 1], f[j] + c * j);
    		}
    		for(j = a[i - 1] - 1;j >= 1; -- j) {
    			r[j] = r[j + 1];
    		}
    		for(j = a[i];j <= m; ++ j) {
    			f[j] = (j - a[i]) * (j - a[i]) + min(l[j] + c * j, r[j] - c * j);
    		}
    	}
    	int ans = 1<<30;
    	for(i = a[n];i <= m; ++ i) ans = min(ans, f[i]);
    	printf("%d
    ",ans);
    }
    
  • 相关阅读:
    微信小程序使用场景及取名“潜”规则
    微信小程序入门——Mustache语法学习
    微信小程序开发需要注意的29个坑
    微信小程序入门——怎么建多个项目?(导入官方Demo程序进行学习)
    精进:如何成为一个很厉害的人---书摘
    软件项目如何控制需求蔓延
    给现有MVC 项目添加 WebAPI
    Web API与国际化
    基于Attribute的Web API路由设置
    NuGet学习笔记1——初识NuGet及快速安装使用
  • 原文地址:https://www.cnblogs.com/suika/p/8678110.html
Copyright © 2020-2023  润新知