zoukankan      html  css  js  c++  java
  • HDU 2829 斜率优化DP Lawrence

    题意:n个数之间放m个障碍,分隔成m+1段。对于每段两两数相乘再求和,然后把这m+1个值加起来,让这个值最小。

    设:

    d(i, j)表示前i个数之间放j个炸弹能得到的最小值

    sum(i)为前缀和,cost(i)为前i个数两两相乘之和。

    则有状态转移方程:

    设0 ≤ l < k < i,且k比l更优,有不等式:

    整理得到,注意不等号方向:

     最后变成了斜率的形式,下面就用一个队列维护即可。

     1 #include <iostream>
     2 #include <cstdio>
     3 #include <cstring>
     4 #include <algorithm>
     5 using namespace std;
     6 
     7 const int maxn = 1000 + 10;
     8 
     9 int n, m;
    10 
    11 int sum[maxn], cost[maxn];
    12 int d[maxn][maxn];
    13 
    14 int head, tail;
    15 int Q[maxn];
    16 
    17 int j;
    18 
    19 int inline Y(int i)
    20 {
    21     return d[i][j-1] + sum[i] * sum[i] - cost[i];
    22 }
    23 
    24 int inline DY(int x1, int x2) { return Y(x2) - Y(x1); }
    25 
    26 int inline DX(int x1, int x2) { return sum[x2] - sum[x1]; }
    27 
    28 int inline DP(int x1, int x2) { return d[x1][j-1] + cost[x2] - cost[x1] - sum[x1]*(sum[x2]-sum[x1]); }
    29 
    30 int main()
    31 {
    32     while(scanf("%d%d", &n, &m) == 2 && n)
    33     {
    34         for(int i = 1; i <= n; i++) scanf("%d", sum + i);
    35         for(int i = 2; i <= n; i++) sum[i] += sum[i - 1];
    36         for(int i = 2; i <= n; i++) cost[i] = cost[i-1] + (sum[i]-sum[i-1])*sum[i-1];
    37 
    38         for(int i = 1; i <= n; i++) d[i][0] = cost[i];
    39         for(j = 1; j <= m; j++)
    40         {
    41             head = tail = 0;
    42             Q[tail++] = 0;
    43             for(int i = 1; i <= n; i++)
    44             {
    45                 while(head + 1 < tail && DY(Q[head], Q[head+1]) <= sum[i] * DX(Q[head], Q[head+1])) head++;
    46                 d[i][j] = DP(Q[head], i);
    47                 while(head + 1 < tail && DY(Q[tail-1], i) * DX(Q[tail-2], Q[tail-1]) <= DY(Q[tail-2], Q[tail-1]) * DX(Q[tail-1], i)) tail--;
    48                 Q[tail++] = i;
    49             }
    50         }
    51 
    52         printf("%d
    ", d[n][m]);
    53     }
    54 
    55     return 0;
    56 }
    代码君

    贴一个四边形不等式优化的代码对比一下:

     1 #include <iostream>
     2 #include <cstdio>
     3 #include <cstring>
     4 #include <algorithm>
     5 using namespace std;
     6 
     7 const int maxn = 1000 + 10;
     8 const int INF = 0x3f3f3f3f;
     9 
    10 int n, m;
    11 int a[maxn], sum[maxn], cost[maxn];
    12 int d[maxn][maxn], s[maxn][maxn];
    13 
    14 
    15 int inline w(int k, int j)
    16 {
    17     return cost[j] - cost[k-1] - sum[k-1] * (sum[j] - sum[k-1]);
    18 }
    19 
    20 int main()
    21 {
    22     while(scanf("%d%d", &n, &m) == 2 && n)
    23     {
    24         m++;
    25 
    26         for(int i = 1; i <= n; i++) scanf("%d", a + i);
    27         for(int i = 1; i <= n; i++) sum[i] = sum[i - 1] + a[i];
    28         for(int i = 2; i <= n; i++) cost[i] = cost[i-1] + sum[i-1] *  a[i];
    29 
    30         memset(d, 0, sizeof(d));
    31         for(int i = 1; i <= m; i++)
    32             for(int j = i + 1; j <= n; j++) d[i][j] = INF;
    33 
    34         for(int i = 1; i <= n; i++) { d[1][i] = cost[i]; s[1][i] = 0; }
    35         for(int i = 2; i <= m; i++)
    36         {
    37             s[i][n+1] = n;
    38             for(int j = n; j >= i; j--)
    39             {
    40                 for(int k = s[i-1][j]; k <= s[i][j+1]; k++)
    41                 {
    42                     int tmp = d[i-1][k] + w(k+1, j);
    43                     if(tmp < d[i][j])
    44                         { d[i][j] = tmp; s[i][j] = k; }
    45                 }
    46             }
    47         }
    48 
    49         printf("%d
    ", d[m][n]);
    50     }
    51 
    52     return 0;
    53 }
    代码君
  • 相关阅读:
    MvvmLight:Command
    TreeView控件
    visual studio背景色
    公共语言运行时
    颜色列表
    自定义控件【旋转按钮,带圆角的边框】
    Loding Animation
    ComboBox前台xaml绑定数据
    Blend一些属性图解
    找到视觉树的方法
  • 原文地址:https://www.cnblogs.com/AOQNRMGYXLMV/p/4693248.html
Copyright © 2011-2022 走看看