四边形不等式优化DP学习小记

简介

有一种DP可以写成四边形不等式,那么可以用一个优化来优化这种DP(一般是二维的,不加优化是 O(n3) )。

四边形不等式

如果 abcd ,那么如果DP式子满足 f(a,c)+f(b,d)f(b,c)+f(a,d) ,那么这就是一个四边形不等式。

先看个例题

题意

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堆石子的数量,计算最小合并代价。
N≤1000

简单DP思路

设f(i,j)为从i合并到j的最小值,枚举中间值k,
那么 f[i,j]=min(f[i,j],f[i,k]+f[k+1,j]+sum[i,j])
这个东西明显是 O(n3)

怎么优化

首先可以发现,上面这个式子很显然满足四边形不等式。
g(i,j) f(i,j) 选用的 k
那么满足不等式
1、 g(i,1)g(i,2)......g(i,n1)g(i,n)
2、 g(1,i)g(2,i)......g(n1,i)g(n,i)
这两个都很显然。
那么我们观察一下g(i,j)的范围,它满足两个不等式:
1、 g(i,j1)g(i,j)
2、 g(i,j)g(i+1,j)

得出结论

g(i,j1)g(i,j)g(i+1,j)
那么我们在转移f(i,j)的时候,k在这个范围内枚举就可以了。
g的初始化:g(i,i)=i。

时间复杂度

这样可以把时间复杂度降到 O(n2)
感性的证明一下,因为g是单调的,所以枚举的k一共就n个。

Code

#include
#include
#include
#include
#include
#include
#define fo(i,a,b) for(i=a;i<=b;i++)
using namespace std;
const int maxn=2007;
int i,j,k,l,t,n,m,ans,p;
int a[maxn],sum[maxn];
int f[maxn][maxn],g[maxn][maxn];
int main(){
    scanf("%d",&n);
    fo(i,1,n)scanf("%d",&a[i]);
    fo(i,1,n)sum[i]=sum[i-1]+a[i];
    memset(f,127,sizeof(f));
    fo(i,1,n)f[i][i]=0,g[i][i]=i;
    fo(l,1,n){
        fo(i,1,n){
            j=i+l;
            if(j>n)break;
            fo(k,g[i][j-1],g[i+1][j]){
                if(f[i][k]+f[k+1][j]+sum[j]-sum[i-1]1][j]+sum[j]-sum[i-1];
                    g[i][j]=k;
                }
            }
        }
    }
    printf("%d\n",f[1][n]);
}

由于本人是个蒟蒻

什么证明比较感性的就不要嘲讽我了。

你可能感兴趣的:(DP,小记,算法小记)