POJ3612 Telephone Wire DP+优化

  题目链接:http://poj.org/problem?id=3612

  状态转移方程容易想出:f[i][j]=min{ f[i-1][j]+c*(j-k)+(j-h[i])^2 | h[i-1]<=k<=maxh && h[i]<=j<=maxh },k为上一个pole的可能高度,maxh为所有poles的最高高度。

  可以算出上面的转移方程复杂度是O(n*100*100),铁定超时。仔细想下还是可以优化的。我们其中(j-h[i])^2与上一个状态无关,可以忽略。只剩下f[i-1][j]+c*(j-k)了,其f[i-1][j]是常数,而c*(j-k)是变量,所以主要考虑c*(j-k)。下面的坐标轴是c*(j-k)随着j变化的值,可以发现,其值是递增或者递减的,因此我们完全可以分情况讨论:

             1.k<=h[i]时,记录h[i-1]-h[i]区间的最小值minl,每当j移动,则minl+=c,然后比较新加进来的h[i+1]。

             2.k>h[i]时,记录每个h[i]-maxh的最小值minr[n],即维护后缀最小值。

  最后就可以在O(1)的时间内找到f[i][j]的最小值了,min{ minl , minr[j] }。当然有些细节要考虑,比如就minr时h[i-1]>h[i]。

                                     val  ^
                                            |      \            /
                                            |        \        /   -->
                                            |          \    /
                                            |            \/
                             ———————————————> j
                                         o |      h[i]
                                            |
                                            |
                                            |

  当然了,还可以化简方程,即 f[i-1][j]+c*(j-k) —> f[i-1][j]+c*k,这样处理起来更方便,方法是一样的。

  最后滚动数组优化下空间。。。

 1 //STATUS:C++_AC_157MS_556KB
 2 #include<stdio.h>
 3 #include<stdlib.h>
 4 #include<string.h>
 5 #include<math.h>
 6 #include<iostream>
 7 #include<string>
 8 #include<algorithm>
 9 #include<vector>
10 #include<queue>
11 #include<stack>
12 using namespace std;
13 #define LL __int64
14 #define pii pair<int,int>
15 #define Max(a,b) ((a)>(b)?(a):(b))
16 #define Min(a,b) ((a)<(b)?(a):(b))
17 #define mem(a,b) memset(a,b,sizeof(a))
18 #define lson l,mid,rt<<1
19 #define rson mid+1,r,rt<<1|1
20 const int N=100010,INF=0x3f3f3f3f,MOD=100000000;
21 const double DNF=100000000000;
22 
23 int f[2][110],h[N],minr[110];
24 int n,c;
25 
26 int main()
27 {
28  //   freopen("in.txt","r",stdin);
29     int i,j,k,maxh,ans,t,minl,p;
30     while(~scanf("%d%d",&n,&c))
31     {
32         ans=INF;
33         maxh=-INF;
34         for(i=0;i<n;i++){
35             scanf("%d",&h[i]);
36             if(h[i]>maxh)maxh=h[i];
37         }
38         for(i=h[0];i<=maxh;i++)f[0][i]=(i-h[0])*(i-h[0]);
39         for(i=p=1;i<n;i++,p=!p){
40             for(minl=INF,j=h[i-1];j<=h[i];j++)
41                 minl=Min(minl,f[!p][j]+c*(h[i]-j));
42             minr[maxh]=f[!p][maxh]+c*(maxh-h[i]);
43             for(j=maxh-1;j>=h[i] && j>=h[i-1];j--)
44                 minr[j]=Min( minr[j+1],f[!p][j]+c*(j-h[i]) );
45             for(;j>=h[i];j--)minr[j]=minr[j+1];
46             for(j=h[i];j<=maxh;j++,minl+=c){
47                 if(j>=h[i-1])minl=Min(minl,f[!p][j]);
48                 f[p][j]=Min( minl,minr[j]-c*(j-h[i]) )+(j-h[i])*(j-h[i]);
49             }
50         }
51         for(p=!p,i=h[n-1];i<=maxh;i++){
52             ans=Min(ans,f[p][i]);
53         }
54 
55         printf("%d\n",ans);
56     }
57     return 0;
58 }
原文地址:https://www.cnblogs.com/zhsl/p/2948624.html