zoukankan      html  css  js  c++  java
  • P2885 [USACO07NOV]电话线Telephone Wire——Chemist

    题目:

    https://www.luogu.org/problemnew/show/P2885

    由于把每一根电线杆增加多少高度不确定,所以很难直接通过某种方法算出答案,考虑动态规划。

    状态:f [ i ] [ j ]表示当第i根电线杆的高度为j时的最小代价和

    转移:当前电线杆的高度只会影响它下一个电线杆的高度,所以就是用前一维的答案来更新后一维。在计算第i根电线杆和第i-1根电线杆时需要计算三部分答案:1.将第i根电线杆增加到j高度的代价 ( j - h [ i ])*(j - h [ i ] )。2.到第i-1根电线杆时的最小花费f [ i-1 ] [ k ](由于我们并不知道第i-1根电线杆的高度,所以需要枚举第i-1根电线杆的高度k)3. 第i根电线杆到第i-1根电线杆之间电线的代价( j - k )*C

    由此我们得到转移方程:f [ i ] [ j ] = ( j - h [ i ] )^2 + min( f [ i - 1 ] [ k ] + | j - k |*C )

    然而这需要我们用三重循环枚举,时间复杂度是O( n*C*C ),会超时(好像有人用这个卡过了。。。)。

    优化:

    我们把绝对值拆开来可以得到一个分段函数:

    f [ i ] [ j ] = ( j - h [ i ] )^2 + min( f [ i - 1 ] [ k ] + j * C - k * C)  ,j>=k

    f [ i ] [ j ] = ( j - h [ i ] )^2 + min( f [ i - 1 ] [ k ] + k * C - j * C )  ,j < k

    我们把 j * C从min中提出来,就变成了:

    f [ i ] [ j ] = ( j - h [ i ] )^2 + j * C + min( f [ i - 1 ] [ k ] - k * C)  ,j>=k

    f [ i ] [ j ] = ( j - h [ i ] )^2 - j * C + min( f [ i - 1 ] [ k ] + k * C )  ,j < k

    我们可以发现,min里面的东西只与k和i有关而与j无关,所以我们可以在外层枚举i,在内层预处理出f [ i - 1 ] [ k ] - k * C的前缀最小值和f [ i - 1 ] [ k ] + k * C的后缀最小值,然后再枚举j,这是就可以直接O(1)调用min(...)了。

    同时由于每一维的状态只与上一维有关且不需要记录答案,所以可以通过滚动数组来将空间复杂度进一步优化到O(C)。

    代码:(注意赋初值等细节)

     1 #include<bits/stdc++.h>
     2 using namespace std;
     3 int read()
     4 {
     5     int ans=0;
     6     char ch=getchar(),last=' ';
     7     while(ch<'0'||ch>'9')
     8     {last=ch;ch=getchar();}
     9     while(ch>='0'&&ch<='9')
    10     {ans=ans*10+ch-'0';ch=getchar();}
    11     if(last=='-')ans=-ans;
    12     return ans;
    13 }
    14 const int M=1e5+10,inf=1e9+7;
    15 int n,C,h[M],f[M][105],m;
    16 //f[i][j]表示第i根电线杆的高度为j时的最小代价和
    17 int l[105],r[105]; 
    18 int main()
    19 {
    20     n=read();C=read();
    21     memset(f,0x3f,sizeof(f));
    22     for(int i=1;i<=n;i++)
    23      h[i]=read(),m=max(m,h[i]);
    24     for(int i=h[1];i<=m;i++)
    25      f[1][i]=(i-h[1])*(i-h[1]);
    26     for(int i=2;i<=n;i++)
    27     {
    28         l[h[i-1]-1]=inf;
    29         r[m+1]=inf;
    30         for(int k=h[i-1];k<=m;k++)
    31          l[k]=min(l[k-1],f[i-1][k]-k*C);
    32         for(int k=m;k>=h[i];k--)
    33          r[k]=min(r[k+1],f[i-1][k]+k*C);
    34         for(int j=h[i-1];j<=m;j++)
    35          if(j>=h[i])f[i][j]=l[j]+(j-h[i])*(j-h[i])+C*j;    
    36         for(int j=m;j>=h[i];j--)
    37          f[i][j]=min(f[i][j],r[j]-C*j+(j-h[i])*(j-h[i]));
    38     }
    39     int ans=inf;
    40     for(int i=h[n];i<=m;i++)
    41      ans=min(ans,f[n][i]);
    42     printf("%d
    ",ans);
    43     return 0;
    44 }
    View Code
  • 相关阅读:
    c中NULL,'\0'和0之间的区别. (the difference between NULL,'\0' and 0 in c)
    python 解析xml文件python parse xml.
    mysql升级 ,MySQL Error: #1558 Column count of mysql.proc is wrong. Expected 20, found 16.
    文献随笔15
    文献笔记11
    文献笔记16
    文献笔记13
    文献笔记17
    文献笔记20
    文献笔记19
  • 原文地址:https://www.cnblogs.com/nopartyfoucaodong/p/9419006.html
Copyright © 2011-2022 走看看