uva 10304 - Optimal Binary Search Tree

Problem E

Optimal Binary Search Tree

Input: standard input

Output: standard output

Time Limit: 30 seconds

Memory Limit: 32 MB

Given a set S = (e1, e2, ..., en) of n distinct elements such that e1 < e2 < ... < en and considering a binary search tree (see the previous problem) of the elements of S, it is desired that higher the query frequency of an element, closer will it be to the root.

The cost of accessing an element ei of S in a tree (cost(ei)) is equal to the number of edges in the path that connects the root with the node that contains the element. Given the query frequencies of the elements of S(f(e1), f(e2, ..., f(en)), we say that the total cost of a tree is the following summation:

f(e1)*cost(e1) + f(e2)*cost(e2) + ... + f(en)*cost(en)

In this manner, the tree with the lowest total cost is the one with the best representation for searching elements of S. Because of this, it is called the Optimal Binary Search Tree.

Input

The input will contain several instances, one per line.

Each line will start with a number 1 <= n <= 250, indicating the size of S. Following n, in the same line, there will be n non-negative integers representing the query frequencies of the elements of S: f(e1), f(e2), ..., f(en). 0 <= f(ei) <= 100.  Input is terminated by end of file.

Output

For each instance of the input, you must print a line in the output with the total cost of the Optimal Binary Search Tree.

 

Sample Input

1 5
3 10 10 10
3 5 10 20

 

Sample Output

0
20
20

这题是最优排序二叉树,首先要知道BST是递归定义的,左子树均小于根节点,右子树均大于根节点,而题目是按严格递增次序给出的(注意节点对应的频率不一定单调),因此可以设想对于序列的某段连续区间,可以枚举根节点,那么根节点左侧自然是左子树了,右侧自然是右子树了,这样就想到了区间dp。复杂度O(n^3)。

每次枚举根节点,左右子树高度均增加1,频率加权和自然增加左右子树频率之和,注意根节点是0层,因此不能加上根节点的频率。可以维护一个前缀和,然后加整段区间和,不要忘了减去根节点的频率。

转移方程:dp[i][j]=min{dp[i][k-1]+dp[k+1][j]+sum[i...j]-a[k]}(i<=k<=j) 这里注意了当k=i或者k=j时,左子树或右子树为空树,此时k-1<i或者k+1>j,这些都是非法的状态,这个时候可以特判,将其设定为0,也可以取k1,k2,见下面代码。总之,目的是为了让这两个状态为0.

代码:

#include<cstdio>
#include<iostream>
#define Maxn 260
using namespace std;

int a[Maxn],sum[Maxn],dp[Maxn][Maxn];
const int inf=1<<30;
int main()
{
    int n;
    while(~scanf("%d",&n)){
        for(int i=1;i<=n;i++)
            scanf("%d",a+i);
        for(int i=1;i<=n;i++){
            sum[i]=sum[i-1]+a[i];
            dp[i][i]=0;
        }
        for(int len=1;len<n;len++)
            for(int i=1,j=1+len;j<=n;i++,j++){
                dp[i][j]=inf;
                int t=sum[j]-sum[i-1];
                for(int k=i;k<=j;k++){
                    int k1=max(i,k-1);
                    int k2=min(k+1,j);
                    dp[i][j]=min(dp[i][j],dp[i][k1]+dp[k2][j]+t-a[k]);
                }
            }
        printf("%d\n",dp[1][n]);
    }
	return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值