2020.07.12日常总结——四边形不等式优化的好题
程序员文章站
2022-04-01 19:59:07
...
最优排序二叉树问题(OBST
,全称如题)的模板题。
给定 个点的点权 ,你需要给它们建一棵排序二叉树,记第 个点的深度为 ,要求这棵排序二叉树:
的值最小。这个值我们称为最小检索次数。
注意,输入平衡树的高度最小,但是它不一定是最优的(甚至可能不如一条链优)。
保证 。
我们可以先确定根,再确定左右子树,因为题目保证有序,所以这样做是肯定对的。
记 表示为区间 建一棵排序二叉树的最小检索次数。考虑如何计算它。
假设 为根,它的深度为 ,贡献为 。左子树 在单独作为一棵树时的最小检索次数为 ,但是因为现在的根是 了,所以它们各自的深度都增加了 ,所以总的检索次数要加上:
右子树类似,记 ,则我们有如下转移式:
直接转移是 的,可以用四边形不等式优化到 ,详见参考代码。
int w[260][260],e[260];
int n,f[260][260],p[260];
inline int cost(int a,int b,int c){
return p[b]-p[a-1]-e[c];
}
int main(){
// freopen("t1.in","r",stdin);
while (~scanf("%d",&n)&&n){
memset(p,0,sizeof(p));
memset(w,0,sizeof(w));
memset(f,127,sizeof(f));
for(int i=1;i<=n;i++){
scanf("%d",&e[i]);
p[i]=p[i-1]+e[i];
}
for(int i=1;i<=n;i++)
f[i][i]=0,w[i][i]=i;
for(int i=1;i<=n;i++)
f[i+1][i]=f[i][i-1]=0;
for(int L=2;L<=n;L++)
for(int j=L;j<=n;j++){
register int i=j-L+1;
for(int k=w[i][j-1];k<=w[i+1][j];k++)
if (f[i][k-1]+f[k+1][j]+cost(i,j,k)<=f[i][j]){
f[i][j]=f[i][k-1]+f[k+1][j]+cost(i,j,k);
w[i][j]=k;//四边形不等式中的记录决策点
}
}
printf("%d\n",f[1][n]);
}
return 0;
}