• 51nod 1022 石子归并 V2 —— DP四边形不等式优化


    题目链接:http://www.51nod.com/onlineJudge/questionCode.html#!problemId=1022

    基准时间限制:1 秒 空间限制:131072 KB 分值: 160 难度:6级算法题
     收藏
     关注
    N堆石子摆成一个环。现要将石子有次序地合并成一堆。规定每次只能选相邻的2堆石子合并成新的一堆,并将新的一堆石子数记为该次合并的代价。计算将N堆石子合并成一堆的最小代价。
     
    例如: 1 2 3 4,有不少合并方法
    1 2 3 4 => 3 3 4(3) => 6 4(9) => 10(19)
    1 2 3 4 => 1 5 4(5) => 1 9(14) => 10(24)
    1 2 3 4 => 1 2 7(7) => 3 7(10) => 10(20)
     
    括号里面为总代价可以看出,第一种方法的代价最低,现在给出n堆石子的数量,计算最小合并代价。
     
    Input
    第1行:N(2 <= N <= 1000)
    第2 - N + 1:N堆石子的数量(1 <= A[i] <= 10000)
    Output
    输出最小合并代价
    Input示例
    4
    1
    2
    3
    4
    Output示例
    19
     
     
    题解:
    1. 一开始想到的是:dp[l][r] = min(dp[l][k]+dp[k+1][r]+w[l][r]), l<=k<r 的区间DP,但时间复杂度为O(n^3),而n<=1e3,所以无法通过。
    2. 然后需要四边形不等式进行优化,四边形不等式优化DP的结论请看:传送门
    3. 优化后:dp[l][r] = min(dp[l][k]+dp[k+1][r]+w[l][r]), s[l][r-1]<=s[l][r]<=s[l+1][r],即s[l][r-1]<=k<=s[l+1][r]
     
    w[][]数组需要满足满足的条件:
    1) 区间包含单调性:被包含的区间的值小于等于包含的区间的值。
    2) 四边形不等式:交叉区间之和小于等于被包含区间加包含区间的值
     
     
     
    代码如下:
     1 #include <iostream>
     2 #include <cstdio>
     3 #include <cstring>
     4 #include <algorithm>
     5 #include <vector>
     6 #include <cmath>
     7 #include <queue>
     8 #include <stack>
     9 #include <map>
    10 #include <string>
    11 #include <set>
    12 using namespace std;
    13 typedef long long LL;
    14 const int INF = 2e9;
    15 const LL LNF = 9e18;
    16 const int MOD = 1e9+7;
    17 const int MAXN = 2e3+10;
    18 
    19 int dp[MAXN][MAXN], sum[MAXN], w[MAXN][MAXN], s[MAXN][MAXN];
    20 int main()
    21 {
    22     int n;
    23     while(scanf("%d", &n)!=EOF)
    24     {
    25         sum[0] = 0;
    26         for(int i = 1; i<=n; i++)   //因为初始时为环(而非一行),所以复制多一份到后面,
    27             scanf("%d",&sum[i]), sum[n+i] = sum[i];
    28 
    29         for(int i = 1; i<2*n; i++)  //求前缀和
    30             sum[i] += sum[i-1];
    31 
    32         for(int l = 1; l<2*n; l++)  //求出每一段区间,最后一次合并所花费的代价(必为质量和)
    33         for(int r = l; r<2*n; r++)
    34             w[l][r] = sum[r]-sum[l-1];
    35 
    36         for(int i = 1; i<2*n; i++)  //初始化单位区间
    37             dp[i][i] = 0, s[i][i] = i;
    38 
    39         for(int len = 2; len<=n; len++) //递推
    40         for(int l = 1; l+len-1<2*n; l++)
    41         {
    42             int r = l+len-1;
    43             dp[l][r] = INF;
    44             for(int k = s[l][r-1]; k<=s[l+1][r]; k++)
    45                 if(dp[l][r]>dp[l][k]+dp[k+1][r]+w[l][r])    //四边形不等式优化
    46                 {
    47                     dp[l][r] = dp[l][k]+dp[k+1][r]+w[l][r];
    48                     s[l][r] = k;
    49                 }
    50         }
    51         int ans = INF;
    52         for(int l = 1; l<=n; l++)   //枚举起点,取最小值
    53             ans = min(ans, dp[l][l+n-1]);
    54         printf("%d
    ", ans);
    55     }
    56 }
    View Code

      

  • 相关阅读:
    C++类构造函数初始化列表
    VC++检测硬件设备状态
    MFC中调用Windows API函数的方式
    DEBUG无法进入断点解决方法
    【转】c++数组初始化
    vc++实现控制USB设备启用与否
    3d图像坐标轴及css3属性的讲解
    Ajax的兼容及Ajax的缓存问题
    Ajax中最有名axios插件(只应用于Ajax)(post方法,官网写错了,应是字符串格式)
    文档碎片及xml讲解
  • 原文地址:https://www.cnblogs.com/DOLFAMINGO/p/8697901.html
Copyright © 2020-2023  润新知