最优二叉搜索树 (dp)

来源:互联网 发布:中国电信云计算基地 编辑:程序博客网 时间:2024/06/05 01:53

题目:

给n个节点以及每个节点的将要被查询的概率pi,然后把它补充成一个满二叉树,用来补充的节点有n+1个,即di ,每个 di 也有一个查询的概率 qi 。构造最优的二叉搜索树,使总的查询次数最少。

最优二叉搜索树:我的理解是,必须保持原二叉树的中序遍历序列不变的前提下,通过将大概率节点尽量排到接近根的位置,使得总查询次数最少的树。它根哈夫曼编码有相似之处,就是贪心的使大概率节点接近树根,但是它不能够改变原树的中序遍历稳定结构。

思路:

因为最优二字,使用的是dp的思想,把整棵树分成若干子树,其子树也是最优二叉搜索树,满足最优子结构。由这些子树组成得到的一棵树即最终的最优二叉搜索树。详见代码。

代码:

#include <bits/stdc++.h>using namespace std;typedef long long ll;const int MAXN=1000+10;const double INF=1e9+7;int n;double p[MAXN];//每一个节点的查找概率double q[MAXN];//伪关键字的搜索概率double dp[MAXN][MAXN];//dp[i][j] 从节点i到节点j构成的最优查找树的PH值的最小值int root[MAXN][MAXN];//root[i][j] 从节点i到节点j构成的最优查找树的根节点double sum[MAXN][MAXN];//sum[i][j] 区间i到j的的区间概率和void solve(){    for(int len=1; len<=n; len++)    {        for(int i=1; i<=n-len+1; i++)        {            int j=i+len-1;            dp[i][j]=INF;            for(int r=i; r<=j; r++)            {                double temp;                temp=dp[i][r-1]+dp[r+1][j]+sum[i][j];                if(temp<dp[i][j])                {                    root[i][j]=r;                    dp[i][j]=temp;                }            }        }    }}void init(){    for(int i=1; i<=n; i++)    {        for(int j=0; j<=n; j++)        {            if(j==i-1)            {                sum[i][j]=q[i-1];                dp[i][j]=q[i-1];            }            else if(j>=i)            {                sum[i][j]=sum[i][j-1]+p[j]+q[j];                if(i==j)                    root[i][j]=i;                dp[i][j]=0;            }            else            {                sum[i][j]=0;                dp[i][j]=0;            }        }    }    sum[n+1][n]=dp[n+1][n]=q[n];}void dfs(int l,int r){    if(l>r)    {        cout<<"{}";        return;    }    cout<<root[l][r];    int Root=root[l][r];    cout<<"{";    dfs(l,Root-1);    cout<<",";    dfs(Root+1,r);    cout<<"}";    return;}int main(){    cout<<"输入待查找关键字的数量:"<<endl;    cin>>n;    cout<<"输入"<<n<<"个待查找关键字的搜索频率:"<<endl;    for(int i=1; i<=n; i++)        cin>>p[i];    cout<<"输入"<<n+1<<"个伪关键字的搜索频率:"<<endl;    for(int i=0; i<=n; i++)        cin>>q[i];    init();    solve();    cout<<"最小PH值:"<<dp[1][n]<<endl<<"最优查找树构造如下:"<<endl;    dfs(1,n);    return 0;}