专栏文章

题解:UVA10304 Optimal Binary Search Tree

UVA10304题解参与者 2已保存评论 2

文章操作

快速查看文章及其快照的属性,并进行相关操作。

当前评论
2 条
当前快照
1 份
快照标识符
@mip9xc82
此快照首次捕获于
2025/12/03 08:33
3 个月前
此快照最后确认于
2025/12/03 08:33
3 个月前
查看原文
思路:
假设以 k(ikj)k(i \le k \le j ) 根,分左右子树。
首先根深度为 00,对答案不做贡献。
左子树:[i,k1][i,k-1] 深度加一,那么总费用要加上: ei+...+ek1e_i+...+e_{k-1}
右子树:同理,[k+1,j][k+1,j] 深度加一,那么总费用要加上: ek+1+...+eje_{k+1}+...+e_j
发现相当于加上了从 iijj 的区间和再减去 eke_k
得出状态转移方程:
fi,j=min(fi,j,fi,k1+fk+1,j+si,jek) f_{i,j}=\min(f_{i,j},f_{i,k-1}+f_{k+1,j}+s_{i,j}-e_k)
code1:
CPP
#include<bits/stdc++.h>
using namespace std;
const int N=256;
int n,m,q,e[N],f[N][N],s[N];
int main()
{
	while(cin>>n){
		memset(f,0x3f3f3f3f,sizeof f);
		memset(s,0,sizeof s);
		for(int i=1;i<=n;i++){
			cin>>e[i];
			f[i][i]=f[i][i-1]=f[i+1][i]=0;
			s[i]=s[i-1]+e[i];
		}	
		for(int len=2;len<=n;len++){
			for(int i=1;i+len-1<=n;i++){
				int j=i+len-1;
				for(int k=i;k<=j;k++){
					f[i][j]=min(f[i][j],f[i][k-1]+f[k+1][j]+(s[j]-s[i-1])-e[k]);
				}
			}
		}
		cout<<f[1][n]<<"\n";
	}
	return 0;
}
时间复杂度:O(n3)O(n^3)
可以进行四边形不等式优化。
code2:
CPP
#include<bits/stdc++.h>
using namespace std;
const int N=256;
int n,m,q,e[N],f[N][N],s[N],w[N][N];
int main()
{
   	while(cin>>n){
		memset(w,0,sizeof w);
		memset(s,0,sizeof s);
		memset(f,0x3f3f3f3f,sizeof f);
		for(int i=1;i<=n;i++){
			cin>>e[i];
			f[i][i]=f[i][i-1]=f[i+1][i]=0;
			s[i]=s[i-1]+e[i];
			w[i][i]=i;
		}	
		for(int len=2;len<=n;len++){
			for(int i=1;i+len-1<=n;i++){
				int j=i+len-1;
				for(int k=w[i][j-1];k<=w[i+1][j];k++) {
					if(f[i][j]>f[i][k-1]+f[k+1][j]+(s[j]-s[i-1])-e[k]){
						f[i][j]=f[i][k-1]+f[k+1][j]+(s[j]-s[i-1])-e[k];
						w[i][j]=k;
					}
				}
			}
		}
		cout<<f[1][n]<<"\n";
	}
	return 0;
}
时间复杂度:O(n2)O(n^2)

评论

2 条评论,欢迎与作者交流。

正在加载评论...