POJ-3612 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 }

 

你可能感兴趣的:(poj)