zoukankan      html  css  js  c++  java
  • POJ 3709 斜率优化DP

    此题有是方程好写,优化很难(对于神犇们,简直太水了)的一道题

    建议做这道题之前先看这道题:http://www.lydsy.com/JudgeOnline/problem.php?id=1010

    题意:

    将一个升序的,有N个元素的序列,分组。要求每组的元素不少于K个,计算出组内各元素与最小元素的之差的和,将每组的这个值加起来,其和要最小。

    思路:

    由以上可得DP方程:

    dp[i]=MIN(dp[j]+sum[i]-sum[j]-(i-j)*arr[j+1]); j<i-k+1

     

    开始斜率优化(不考虑每组不少于K个元素):

    1.证明较优决策点对后续状态影响的持续性

      证明很简单,不证了,有兴趣的话,参考上一篇文章

     

    2.求斜率方程:一般化为左边是JK,右边是I的形式

      假设J<K,且在K点的决策比J好,则有

     dp[j]+sum[i]-sum[j]-(i-j)*arr[j+1]>= dp[k]+sum[i]-sum[k]-(i-k)*arr[k+1]

    化简得:

      dp[j]-dp[k]-sum[j]+sum[k]+j*arr[j+1]-k*arr[k+1]>=i* (arr[j+1]-arr[k+1])

     

    G(k,j)= dp[j]-dp[k]-sum[j]+sum[k]+j*arr[j+1]-k*arr[k+1]

       S(k,j)= arr[j+1]-arr[k+1]

     

    则上式化为G(k,j)>=i*S(k,j)

    G(k,j)/S(k,j)<=i 记住变号,因为S(k,j)<0

    X(k,j)= G(k,j)/S(k,j)

    所以斜率方程:X(k,j)<=i

     

    3.规定队列的维护规则

    队首维护:

      假设A,B(A<B)是队首元素,X(B,A)<=i,BA,删除A,否则不需维护.

     

    队尾维护:

        假设A,B,C(A<B<C)是队尾元素

    a.X(B,A)<=i,X(C,B)<=i,CB,BA

    b.X(B,A)<=i,X(C,B)>i,BC,BA,B为极大值

    c.X(B,A)>i,AB

     

    a,c情况直接删掉B,b情况保留.b情况可改为X(B,A)<X(C,B)

     

    好,以下考虑每组不少于K个元素这个限制。

    要解决这个限制,只需延迟加入的时机即可。

    若延迟K-1个回合加入,有可能使前一组的个数少于K个。

    若延迟2*k-1个回合加入,则不会出现这情况。但此时加入的数应是i-k+1(假设是第I回合)

    第一次做斜率优化DP,照着题解写的,以上内容转自:http://blog.sina.com.cn/s/blog_5f5353cc0100jxxo.html

    代码按照题解思路写的:

    DP真的好神奇!~

    View Code
     1 #include <cstdio>
     2 #include <cstring>
     3 #include <cstdlib>
     4 #include <iostream>
     5 
     6 #define N 505000 
     7 
     8 using namespace std;
     9 
    10 int n,k,tt;
    11 __int64 dp[N],sum[N],a[N],q[N];
    12 
    13 void read()
    14 {
    15     scanf("%d%d",&n,&k);
    16     for(int i=1;i<=n;i++)
    17     {
    18         scanf("%I64d",&a[i]);
    19         sum[i]=sum[i-1]+a[i];
    20     }
    21 }
    22 
    23 __int64 G(int y,int x)
    24 {
    25     return dp[x]-dp[y]-sum[x]+sum[y]+x*a[x+1]-y*a[y+1];
    26 }
    27 
    28 __int64 S(int y,int x)
    29 {
    30     return a[x+1]-a[y+1];
    31 }
    32 
    33 void go()
    34 {
    35     dp[0]=0;
    36     int h=1,t=1;
    37     q[t++]=0;
    38     for(int i=1,x,y,z;i<=n;i++)
    39     {
    40         while(h<t-1&&G(q[h+1],q[h])>=i*S(q[h+1],q[h])) h++;//把不可能成为最优值的出队 
    41         
    42         dp[i]=dp[q[h]]+sum[i]-sum[q[h]]-(i-q[h])*a[q[h]+1];
    43         
    44         if(i>=2*k-1) q[t++]=i-k+1;//延迟更新 
    45         
    46         for(int j=t-2;j-1>=h;j--)
    47         {
    48             x=q[j-1]; y=q[j]; z=q[j+1];
    49             if(G(y,x)*S(z,y)>=G(z,y)*S(y,x)) q[j]=q[--t];
    50             else break;
    51         }
    52     }
    53     printf("%I64d\n",dp[n]);
    54 }
    55 
    56 int main()
    57 {
    58     scanf("%d",&tt);
    59     while(tt--)
    60     {
    61         read();
    62         go();
    63     }
    64     return 0;
    65 }

     

    没有人能阻止我前进的步伐,除了我自己!
  • 相关阅读:
    Effective Java 19 Use interfaces only to define types
    Effective Java 18 Prefer interfaces to abstract classes
    Effective Java 17 Design and document for inheritance or else prohibit it
    Effective Java 16 Favor composition over inheritance
    Effective Java 15 Minimize mutability
    Effective Java 14 In public classes, use accessor methods, not public fields
    Effective Java 13 Minimize the accessibility of classes and members
    Effective Java 12 Consider implementing Comparable
    sencha touch SortableList 的使用
    sencha touch dataview 中添加 button 等复杂布局并添加监听事件
  • 原文地址:https://www.cnblogs.com/proverbs/p/2713104.html
Copyright © 2011-2022 走看看