• 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 }
  • 相关阅读:
    触发器基本使用
    查询结果合并用逗号分隔
    查询报表增加小计功能
    sql语句格式化数字(前面补0)
    如何在选择画面中创建下拉列表(drop down list)-as list box
    如何更改函数的函数组(function group)
    ABAP语言中如何定义嵌套内表(nested internal table)
    [REUSE_ALV_GRID_DISPLAY]如何指定单元格颜色
    如何创建嵌套动态内表(Nested dynamic internal table)
    如何根据方法名(method)查找所在类(class)-SE84
  • 原文地址:https://www.cnblogs.com/zhsl/p/2948624.html
Copyright © 2020-2023  润新知