1. 程式人生 > >bzoj 1705: [Usaco2007 Nov]Telephone Wire 架設電話線——dp

bzoj 1705: [Usaco2007 Nov]Telephone Wire 架設電話線——dp

++ phone str color 工程 最好 inpu height getch

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。
———————————————————————————— f[i][j]=min(f[i-1][k]+abs(j-k)*c+(h[i]-j)*(h[i]-j); 我們可以分兩類 1 j>k f[i][j]=min(f[i-1][k]-c*k+c*j+(h[i]-j)*(h[i]-j) 可以發現轉移方程與k無關 所以可以維護前綴min‘就好了 j < k 是差不多的維護一下後綴mn就可以了 技術分享
#include<cstdio>
#include<cstring>
#include<algorithm>
using std::min;
using
std::max; const int M=1e5+7,inf=0x3f3f3f3f; int read(){ int ans=0,f=1,c=getchar(); while(c<0||c>9){if(c==-) f=-1; c=getchar();} while(c>=0&&c<=9){ans=ans*10+(c-0); c=getchar();} return ans*f; } int n,c,ans,mn; int h[M],f[M][107]; int main(){ n=read(); c=read(); for(int i=1;i<=n;i++) h[i]=read(); memset(f,0x3f,sizeof(f)); for(int i=h[1];i<=100;i++) f[1][i]=(h[1]-i)*(h[1]-i); for(int k=2;k<=n;k++){ mn=inf; for(int i=h[k-1];i<max(h[k-1],h[k]);i++) mn=min(mn,f[k-1][i]-c*i); for(int i=h[k];i<=100;i++){ mn=min(mn,f[k-1][i]-c*i); f[k][i]=mn+c*i+(h[k]-i)*(h[k]-i); } mn=inf; for(int i=100;i>=h[k];i--){ if(i>=h[k-1]) mn=min(mn,f[k-1][i]+c*i); f[k][i]=min(f[k][i],mn-c*i+(h[k]-i)*(h[k]-i)); } } ans=inf; for(int i=1;i<=100;i++) ans=min(ans,f[n][i]); printf("%d\n",ans); return 0; }
View Code

bzoj 1705: [Usaco2007 Nov]Telephone Wire 架設電話線——dp