bzoj1705[Usaco2007 Nov]Telephone Wire 架设电话线(dp优化)
1705: [Usaco2007 Nov]Telephone Wire 架设电话线
Time Limit: 5 Sec Memory Limit: 64 MBSubmit: 441 Solved: 247
[Submit][Status][Discuss]
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米。
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。
输出说明:
最好的改造方法是: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]+|j-k|*c+(a[i]-j)*(a[i]-j)) 摘出与k无关项得 f[i][j] = min(f[i-1][k]+|j-k|*c) + (a[i]-j)*(a[i]-j) 记P = min(f[i-1][k]+|j-k|*c) , Q = (a[i]-j)*(a[i]-j) 则f[i][j] = P + Q P = min(A,B),其中 A = min(f[i-1][k]+(j-k)*c) (k<=j) B = min(f[i-1][k]+(k-j)*c) (k>j) A = min(f[i-1][k]-k*c) + j*c B = min(f[i-1][k]+k*c) - j*c 记C[X][i] = min(f[X][k] - k*c) k∈[1,i] 记D[X][i] = min(f[X][k] + k*c) k∈[i,n] 则A = C[i-1][j] + j*c 则B = D[i-1][j+1] - j*c 显然C、D在任何时刻只需保存X=i-1一行的值 注意高度只能增高,所以h[i]∈[a[i],100] 利用辅助数组优化后,时间复杂度降为O(N*100) */ #include<iostream> #include<cstdio> #include<cstring> #define N 100010 #define H 110 #define inf 0x3f3f3f3f using namespace std; int n,c,h,P,Q,A,B; int a[N],C[H],D[H],f[N][H]; int main() { scanf("%d%d",&n,&c); for(int i=1;i<=n;i++) scanf("%d",&a[i]); h=a[1]; for(int i=1;i<=n;i++) h=max(h,a[i]); h=min(h,100); memset(f,0x3f,sizeof f); for(int i=1;i<=n;i++) { if(i==1) for(int j=a[i];j<=h;j++) f[1][j]=(j-a[1])*(j-a[1]); else { for(int j=a[i];j<=h;j++) { Q=(j-a[i])*(j-a[i]); A=C[j]+j*c; B=D[j+1]-j*c; P=min(A,B); f[i][j]=P+Q; } } C[0]=D[h+1]=inf; for(int j=1;j<=h;j++) C[j]=min(C[j-1],f[i][j]-j*c); for(int j=h;j>=1;j--) D[j]=min(D[j+1],f[i][j]+j*c); } int ans=inf; for(int i=1;i<=h;i++) ans=min(ans,f[n][i]); printf("%d\n",ans); return 0; return 0; return 0; }
折花枝,恨花枝,准拟花开人共卮,开时人去时。
怕相思,已相思,轮到相思没处辞,眉间露一丝。