有一种DP可以写成四边形不等式,那么可以用一个优化来优化这种DP(一般是二维的,不加优化是 O(n3) )。
如果 a≤b≤c≤d ,那么如果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
设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,n−1)≤g(i,n)
2、 g(1,i)≤g(2,i)≤......≤g(n−1,i)≤g(n,i)
这两个都很显然。
那么我们观察一下g(i,j)的范围,它满足两个不等式:
1、 g(i,j−1)≤g(i,j)
2、 g(i,j)≤g(i+1,j)
g(i,j−1)≤g(i,j)≤g(i+1,j)
那么我们在转移f(i,j)的时候,k在这个范围内枚举就可以了。
g的初始化:g(i,i)=i。
这样可以把时间复杂度降到 O(n2) 。
感性的证明一下,因为g是单调的,所以枚举的k一共就n个。
#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]);
}
什么证明比较感性的就不要嘲讽我了。