四边形不等式优化石子合并Codevs3002题解

  • 题目描述 Description

    有n堆石子排成一列,每堆石子有一个重量w[i], 每次合并可以合并相邻的两堆石子,一次合并的代价为两堆石子的重量和w[i]+w[i+1]。问安排怎样的合并顺序,能够使得总合并代价达到最小。

  • 输入描述 Input Description

    第一行一个整数n(n≤3000)

    第二行n个整数w1,w2...wn(wi≤3000)

  • 输出描述 Output Description

    一个整数表示最小合并代价

  • 样例输入 Sample Input

    4

    4 1 1 4

  • 样例输出 Sample Output

    18

  • 题解

    写出来普通的区间dp方程,发现时间复杂度是O(n3)的,不能通过本题。这种题可以使用四边形不等式优化。

    有一篇叫“动态规划加速原理之四边形不等式”的文章对四边形不等式介绍得很好。

    形如本题的状态转移方程都可以用四边形不等式优化,这里不再证明。(实在不会证可以拿优化过的和裸dp的对拍啊,四边形不等式不难写)

    这里介绍一下边界:

    只有一堆石子时,f(i,i)=0,f(i,i)的最大值在i处取到,所以f(i,i)对应决策变量最大值为s(i,i)=i。

    只要分析好边界的值是自变量等于什么时取到的,自然可以得到决策变量最大值的边界。以后转移时只需在更新f的同时更新s即可。

  • Code
#include <cstdio>
#include <algorithm>
using namespace std;
const int maxn = 3010, oo = 1000000000;
int f[maxn][maxn], s[maxn][maxn];
int n, a[maxn], w[maxn][maxn];
void init()
{
    scanf("%d", &n);
    for(int i = 1; i <= n; ++i)
    {
        scanf("%d", &a[i]);
        w[i][i] = a[i];
    }
    for(int i = 1; i <= n; ++i) for(int j = i + 1; j <= n; ++j)
        w[i][j] = w[i][j - 1] + a[j];
}
void work()
{
    for(int i = 1; i <= n; ++i) s[i][i] = i;
    for(int p = 1; p < n; ++p)  for(int i = 1; i <= n - p; ++i)
    {
        int j = i + p;
        f[i][j] = oo;
        for(int k = s[i][j - 1]; k <= s[i + 1][j]; ++k)
            if(f[i][j] > f[i][k] + f[k + 1][j] + w[i][j])
            {
                f[i][j] = f[i][k] + f[k + 1][j] + w[i][j];
                s[i][j] = k;
                //因为这里k是递增的,所以不用取max
            }
    }
    printf("%d", f[1][n]);
}
int main()
{
    init();
    work();
    return 0;
}
时间: 2025-01-09 19:36:04

四边形不等式优化石子合并Codevs3002题解的相关文章

四边形不等式(石子合并)

动态规区间dp做这道题的话应该是n^3,下面的代码优化到了n^2,用四边形不等式优化. 设mid[i][j]是dp[i][j]的最优解的断点,即它左区间的右端点,那么mid[i][j-1]<=mid[i][j]<=mid[i+1][j],所以在求解dp[i][j]时,枚举k可以只枚举这两个值之间枚举就好, 程序要先枚举区间长度,在枚举左端点,枚举每个区间长度时,他们的k总是只从1到n,只走一遍,所以这就相当于优化了一层,变成了O(n2)的. 比如len长度为3时,dp[1][3]只会枚举mid

合并石子 四边形不等式优化

题目描述 有一排石子,共n 堆.现要将石子有次序地合并成一堆.规定每次只能选相邻的2 堆石子合并成新的一堆,并将新的一堆石子数记为该次合并的得分.试设计一个算法,计算出将n堆石子合并成一堆的最小得分. 题解 首先由直接动态规划的方法来做,即 for(int i=1;i<=n;i++) for(int j=i;j<=n;j++) for(int k=i;k<=j;k++) { f[i][j]=min(f[i][j],f[i][k]+f[k+1][j]+cost[j]-cost[i-1]);

四边形不等式优化DP——石子合并问题 学习笔记

好方啊马上就要区域赛了连DP都不会QAQ 毛子青<动态规划算法的优化技巧>论文里面提到了一类问题:石子合并. n堆石子.现要将石子有次序地合并成一堆.规定每次只能选相邻的2堆石子合并成新的一堆,并将新的一堆石子数记为该次合并的得分. 求出将n堆石子合并成一堆的最小得分和最大得分以及相应的合并方案. 设m[i,j]表示合并d[i..j]所得到的最小得分. 状态转移方程: 总的时间复杂度为O(n3). [优化方案] 四边形不等式: m[i,j]满足四边形不等式 令s[i,j]=max{k | m[

石子合并(四边形不等式优化dp)

该来的总是要来的———————— 经典问题,石子合并. 对于 f[i][j]= min{f[i][k]+f[k+1][j]+w[i][j]} From 黑书 凸四边形不等式:w[a][c]+w[b][d]<=w[b][c]+w[a][d](a<b<c<d) 区间包含关系单调: w[b][c]<=w[a][d](a<b<c<d) 定理1:  如果w同时满足四边形不等式和决策单调性 ,则f也满足四边形不等式 定理2:  若f满足四边形不等式,则决策s满足 s[i

[51nod 1022] 石子归并v2 [dp+四边形不等式优化]

题面: 传送门 思路: 加强版的石子归并,现在朴素的区间dp无法解决问题了 首先我们破环成链,复制一条一样的链并粘贴到原来的链后面,变成一个2n长度的序列,在它上面dp,效率O(8n^3) 显然是过不了的,需要优化 注意:dp的转移如下:dp[i][j]=min(dp[i][k]+dp[k+1][j]+sum(i,j)),其中sum(i,j)表示i到j的价值和,满足区间单调性 因此dp[i][j]也满足区间单调性,可以用四边形不等式优化 我们令s[i][j]等于让dp[i][j]取最小值的那个K

区间dp+四边形不等式优化

区间dp+四边形优化 luogu:p2858 题意 给出一列数 \(v_i\),每天只能取两端的数,第 j 天取数价值为\(v_i \times j\),最大价值?? 转移方程 dp[i][j] :n天卖掉i..j货物的收益 dp[begin][end]=max(dp[begin][end-1]+value[end]*(n-len+1) ,dp[begin+1][end]+value[begin]*(n-len+1)); 注意理解 代码 递推形式 #include<bits/stdc++.h>

四边形不等式优化

四边形不等式优化条件(转自这里) 在动态规划中,经常遇到形如下式的转台转移方程: m(i,j)=min{m(i,k-1),m(k,j)}+w(i,j)(i≤k≤j)(min也可以改为max) 上述的m(i,j)表示区间[i,j]上的某个最优值.w(i,j)表示在转移时需要额外付出的代价.该方程的时间复杂度为O(N^3). 下面我们通过四边形不等式来优化上述方程,首先介绍什么是"区间包含的单调性"和"四边形不等式" (1)区间包含的单调性:如果对于i≤i'<j≤

[dp专题-四边形不等式优化]51nod 1022

? 1021?石子归并?V1 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(1

动态规划之四边形不等式优化

四边形不等式 设函数\(w(x,y)\)是定义在\(Z\)上的函数,若对于任意\(a,b,c,d \in Z\),其中\(a\leq b \leq c \leq d\), 都有\(w(a,d)+w(b,c)\ge w(a,c)+w(b,d)\),则称函数\(w\)满足四边形不等式 推论: 设函数\(w(x,y)\)是定义在\(Z\)上的函数,若对于任意\(a,b \in Z\),其中\(a<b\), 都有\(w(a,b+1)+w(a+1,b) \ge w(a,b)+w(a+1,b+1)\),则函