codevs 3002石子归并

来源:互联网 发布:软件外包项目管理制度 编辑:程序博客网 时间:2024/06/05 12:46

四边形不等式第一题……然而写起来似乎一帆风顺?

非常基础的区间dp,但是直接做是n^3的,这是个标准的2D/1D,我们可以想到四边形不等式

我们设f[i][j]表示完成归并区间[i,j]的最小代价

那么转移很容易想到

关于四边形不等式,黑书上有三个定理,我不会证,所以要记好

四边形不等式:w(i,j)+w(i+1,j-1)>=w(i,j-1)+w(i+1,j)

决策单调性:w(i,j)>=w(l,r) 其中(l,r)⊆(i,j)

如果w(i,j)满足四边形不等式和决策单调性,那么f也满足四边形不等式

那么就可以做了,四边形不等式的题有一种套路做法

设让f[i][j]最优的k为k[i][j],那么满足k[i][j-1]<=k[i][j]<=k[i+1][j]

那么就可以做了,决策范围由[i,j]变到了[k[i][j-1],k[i+1][j]],因为k是单调的,所以当j-i一定的时候转移总共只要O(n)

也就是说平均转移O(1)

然后就ac了

ac code:

#include <cstdio>
#include <cstring>
using namespace std;
int n,i,j;
int w[3050];
int f[3050][3050];
int k[3050][3050];
int main()
{
scanf("%d",&n);
w[0]=0;
for (i=1;i<=n;i++){
scanf("%d",&w[i]);
w[i]+=w[i-1];
}
for (i=1;i<=n;i++)
for (j=1;j<=n;j++) f[i][j]=100000000;
for (i=1;i<=n;i++) f[i][i]=0;
for (i=1;i<n;i++) f[i][i+1]=w[i+1]-w[i-1];
for (i=1;i<n;i++) k[i][i+1]=i;
for (j=2;j<=n;j++)
for (i=1;i<n;i++) if (i+j<=n){
int l;
for (l=k[i][i+j-1];l<=k[i+1][i+j];l++) if (f[i][l]+f[l+1][i+j]+w[i+j]-w[i-1]<f[i][i+j]){
f[i][i+j]=f[i][l]+f[l+1][i+j]+w[i+j]-w[i-1];
k[i][i+j]=l;
}
}
printf("%d\n",f[1][n]);
return 0;
}

1 1
原创粉丝点击