uva 10304 Optimal Binary Search Tree

原题:
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
大意:
给你一个n个数,这个数形成一个二叉排序树。这n个数每个数都给你一个频率f(ei),每个数还有各自的代价cost(ei),带价值是这个节点到跟节点的路径长度。现在问你求sigma f(ei)*cost(ei)的值是多少。

给出一组数据
4 1 2 3 4
答案是8

#include<iostream>
#include<algorithm>
#include<map>
#include<string>
#include<cstring>
#include<sstream>
#include<cstdio>
#include<vector>
#include<cmath>
#include<stack>
#include<queue>
#include<iomanip>
#include<set>
#include<fstream>
#include <limits.h>
using namespace std;
//fstream output,input;

int dp[255][255];
int n;
int cost[255];
int sum[255];
int main()
{
    ios::sync_with_stdio(false);
    int l,i,j,k;
    while(cin>>n)
    {
        sum[0]=0;
        for(int i=1;i<=n;i++)
        {
            cin>>cost[i];
            sum[i]=sum[i-1]+cost[i];
        }
        memset(dp,0,sizeof(dp));
        for(l = 2;l<=n;l++)
        {
            for(i=1 ;i<=n-l+1;i++)
            {
                j=i+l-1;
                dp[i][j]=99999999;
                for(k=i+1;k<j;k++)
                {
                    dp[i][j]=min(dp[i][j],dp[i][k-1]+dp[k+1][j]+sum[j]-sum[i-1]-cost[k]);//k节点当根
                }
                dp[i][j]=min(dp[i][j],dp[i][j-1]+sum[j]-sum[i-1]-cost[j]);//j节点当根
                dp[i][j]=min(dp[i][j],dp[i+1][j]+sum[j]-sum[i-1]-cost[i]);//i节点当根
            }
        }
        cout<<dp[1][n]<<endl;
/* for(i=1 ;i<=n;i++) { for(j=1;j<=n;j++) cout<<dp[i][j]<<" "; cout<<endl; }*/
    }
    return 0;
}




解答:
首先考虑一组数ai到aj,ai,…..ak,……aj 。由于是二叉查找树,那么任何节点都能当做根节点,而且对应要求的目标值也不相同。现在考虑ak作为根节点,则这个树的左侧有ai->ak-1的节点,右侧有ak+1->aj的节点。
可以判断出来这是一个区间dp,状态方程大概是这个模样 dp[i][j]=min(dp[i][j],dp[i][k-1]+dp[k+1][j]+???)
。现在考虑状态转移,也就是那3个问号。之前求解出来的子区间dp[i][k-1]和dp[k+1][j]是已经求解出来的最优子目标值,如果现在把这两个区间连接到节点k上,则树的高度增加1,这里ak节点到根节点(也就是到自己)的距离是0。除了ak节点自己以外,连接在ak节点的上的所有节点路径都会加1。由于ai->ak-1和ak+1->aj的深度增加1,相应的cost(ei)也应该加上一遍。cost(ek)不用加,所以转移公式为sum[j]-sum[i-1]-cost[k]。这里sum[i]为前i个cost的和。
如图:uva 10304 Optimal Binary Search Tree_第1张图片

你可能感兴趣的:(dp,uva)